Skip to content

feat: send notification for joining/leaving an engagement (resolves #2578) #2614

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

Merged
merged 5 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/Http/Controllers/EngagementController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
use App\Models\Project;
use App\Models\User;
use App\Notifications\AccessNeedsFacilitationRequested;
use App\Notifications\JoinedEngagement;
use App\Notifications\LeftEngagement;
use App\Notifications\OrganizationAddedToEngagement;
use App\Notifications\OrganizationRemovedFromEngagement;
use App\Notifications\ParticipantInvited;
Expand Down Expand Up @@ -625,6 +627,7 @@ public function join(Request $request, Engagement $engagement): RedirectResponse
$engagement->participants()->save(Auth::user()->individual, ['status' => 'confirmed']);

$engagement->project->notify(new ParticipantJoined($engagement));
Auth::user()->notify(new JoinedEngagement($engagement));

flash(__('You have successfully signed up for this engagement.'), 'success|'.__('You have successfully signed up for this engagement.', [], 'en'));

Expand Down Expand Up @@ -708,6 +711,7 @@ public function leave(Request $request, Engagement $engagement): RedirectRespons
Auth::user()->individual->engagements()->detach($engagement->id);

$engagement->project->notify(new ParticipantLeft($engagement));
Auth::user()->notify(new LeftEngagement($engagement));

flash(__('You have successfully left this engagement.'), 'success|'.__('You have successfully left this engagement.', [], 'en'));

Expand Down
57 changes: 57 additions & 0 deletions app/Notifications/JoinedEngagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace App\Notifications;

use App\Models\Engagement;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\VonageMessage;

class JoinedEngagement extends PlatformNotification
{
public Engagement $engagement;

public mixed $projectable;

public function __construct(Engagement $engagement)
{
$this->engagement = $engagement;
$this->projectable = $this->engagement->project->projectable;
}

public function toMail(): MailMessage
{
return (new MailMessage)
->subject(__('Signed up for :engagement', ['engagement' => $this->engagement->getTranslation('name', locale())]))
->markdown(
'mail.joined-engagement',
[
'engagement' => $this->engagement,
'projectable' => $this->projectable,
]
);
}

public function toVonage(): VonageMessage
{
return (new VonageMessage)
->content(
__('You have signed up for :engagement by :projectable', [
'engagement' => $this->engagement->getTranslation('name', locale()),
'projectable' => $this->projectable->getTranslation('name', locale()),
]).'. '.__(
'View this engagement at :url.',
[
'url' => localized_route('engagements.show', $this->engagement),
]
)
)
->unicode();
}

public function toArray(): array
{
return [
'engagement_id' => $this->engagement->id,
];
}
}
57 changes: 57 additions & 0 deletions app/Notifications/LeftEngagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace App\Notifications;

use App\Models\Engagement;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\VonageMessage;

class LeftEngagement extends PlatformNotification
{
public Engagement $engagement;

public mixed $projectable;

public function __construct(Engagement $engagement)
{
$this->engagement = $engagement;
$this->projectable = $this->engagement->project->projectable;
}

public function toMail(): MailMessage
{
return (new MailMessage)
->subject(__('Left :engagement', ['engagement' => $this->engagement->getTranslation('name', locale())]))
->markdown(
'mail.left-engagement',
[
'engagement' => $this->engagement,
'projectable' => $this->projectable,
]
);
}

public function toVonage(): VonageMessage
{
return (new VonageMessage)
->content(
__('You have left :engagement by :projectable', [
'engagement' => $this->engagement->getTranslation('name', locale()),
'projectable' => $this->projectable->getTranslation('name', locale()),
]).'. '.__(
'View this engagement at :url.',
[
'url' => localized_route('engagements.show', $this->engagement),
]
)
)
->unicode();
}

public function toArray(): array
{
return [
'engagement_id' => $this->engagement->id,
];
}
}
47 changes: 47 additions & 0 deletions app/View/Components/Notification/JoinedEngagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\View\Components\Notification;

use App\Models\Engagement;
use App\Models\Organization;
use App\Models\RegulatedOrganization;
use App\View\Components\Notification;
use Illuminate\Contracts\View\View;
use Illuminate\Notifications\DatabaseNotification;

class JoinedEngagement extends Notification
{
public Engagement $engagement;

public mixed $projectable;

public function __construct(DatabaseNotification $notification)
{
$this->engagement = Engagement::find($notification->data['engagement_id']);
$this->projectable = $this->engagement->project->projectable;
/** @var Organization|RegulatedOrganization */
$projectable = $this->projectable;
$this->title = __('Engagement joined');
$this->body = safe_markdown('You have signed up for [:engagement](:engagement_url) by [:projectable](:projectable_url).', [
'engagement' => $this->engagement->getTranslation('name', locale()),
'engagement_url' => localized_route('engagements.show', $this->engagement),
'projectable' => $projectable->getTranslation('name', locale()),
'projectable_url' => localized_route($projectable->getRoutePrefix().'.show', $projectable),
]);
$this->interpretation = __('Engagement joined', [], 'en');

parent::__construct($notification);
}

public function render(): View
{
return view('components.notification.joined-engagement', [
'notification' => $this->notification,
'read' => ! is_null($this->notification->read_at),
'title' => $this->title,
'body' => $this->body,
'engagement' => $this->engagement,
'interpretation' => $this->interpretation,
]);
}
}
47 changes: 47 additions & 0 deletions app/View/Components/Notification/LeftEngagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\View\Components\Notification;

use App\Models\Engagement;
use App\Models\Organization;
use App\Models\RegulatedOrganization;
use App\View\Components\Notification;
use Illuminate\Contracts\View\View;
use Illuminate\Notifications\DatabaseNotification;

class LeftEngagement extends Notification
{
public Engagement $engagement;

public mixed $projectable;

public function __construct(DatabaseNotification $notification)
{
$this->engagement = Engagement::find($notification->data['engagement_id']);
$this->projectable = $this->engagement->project->projectable;
/** @var Organization|RegulatedOrganization */
$projectable = $this->projectable;
$this->title = __('Left engagement');
$this->body = safe_markdown('You left [:engagement](:engagement_url) by [:projectable](:projectable_url).', [
'engagement' => $this->engagement->getTranslation('name', locale()),
'engagement_url' => localized_route('engagements.show', $this->engagement),
'projectable' => $projectable->getTranslation('name', locale()),
'projectable_url' => localized_route($projectable->getRoutePrefix().'.show', $projectable),
]);
$this->interpretation = __('Left engagement', [], 'en');

parent::__construct($notification);
}

public function render(): View
{
return view('components.notification.left-engagement', [
'notification' => $this->notification,
'read' => ! is_null($this->notification->read_at),
'title' => $this->title,
'body' => $this->body,
'engagement' => $this->engagement,
'interpretation' => $this->interpretation,
]);
}
}
12 changes: 12 additions & 0 deletions resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@
"engagement description (French)": "engagement description (French)",
"Engagement estimate has been submitted for your approval": "Engagement estimate has been submitted for your approval",
"engagement format": "engagement format",
"Engagement joined": "Engagement joined",
"Engagement materials": "Engagement materials",
"Engagement meetings": "Engagement meetings",
"engagement name": "engagement name",
Expand Down Expand Up @@ -858,6 +859,8 @@
"Leave engagement": "Leave engagement",
"Leave organization": "Leave organization",
"Leave this organization": "Leave this organization",
"Left :engagement": "Left :engagement",
"Left engagement": "Left engagement",
"Light grey on grey": "Light grey on grey",
"Light theme": "Light theme",
"Link copied!": "Link copied!",
Expand Down Expand Up @@ -1480,6 +1483,7 @@
"show up on search results for them": "show up on search results for them",
"Signed language for interpretation": "Signed language for interpretation",
"signed language for translation": "signed language for translation",
"Signed up for :engagement": "Signed up for :engagement",
"Sign in": "Sign in",
"Sign language interpretation": "Sign language interpretation",
"Sign language interpretations": "Sign language interpretations",
Expand Down Expand Up @@ -1766,7 +1770,10 @@
"Video": "Video",
"Video recording": "Video recording",
"View": "View",
"View engagement": "View engagement",
"View engagement details": "View engagement details",
"View page": "View page",
"View this engagement at :url.": "View this engagement at :url.",
"Virtual or in-person": "Virtual or in-person",
"Virtual – phone call": "Virtual – phone call",
"Virtual – web conference": "Virtual – web conference",
Expand Down Expand Up @@ -1962,9 +1969,13 @@
"You have joined :invitationable as a :role": "You have joined :invitationable as a :role",
"You have joined as a :role": "You have joined as a :role",
"You have joined the team.": "You have joined the team.",
"You have left :engagement by :projectable": "You have left :engagement by :projectable",
"You have left [:engagement](:engagement_url) by [:projectable](:projectable_url).": "You have left [:engagement](:engagement_url) by [:projectable](:projectable_url).",
"You have not added any engagements yet.": "You have not added any engagements yet.",
"You have not passed the quiz.": "You have not passed the quiz.",
"You have now completed this course. Your certificate of completion has been sent to your email.": "You have now completed this course. Your certificate of completion has been sent to your email.",
"You have signed up for :engagement by :projectable": "You have signed up for :engagement by :projectable",
"You have signed up for [:engagement](:engagement_url) by [:projectable](:projectable_url).": "You have signed up for [:engagement](:engagement_url) by [:projectable](:projectable_url).",
"You have successfully added :notificationable to your list.": "You have successfully added :notificationable to your list.",
"You have successfully added :organization as the Community Organization you are consulting with for this engagement.": "You have successfully added :organization as the Community Organization you are consulting with for this engagement.",
"You have successfully added the Community Organization you are consulting with for this engagement.": "You have successfully added the Community Organization you are consulting with for this engagement.",
Expand All @@ -1987,6 +1998,7 @@
"You have successfully submitted an estimate request.": "You have successfully submitted an estimate request.",
"You have successfully unblocked.": "You have successfully unblocked.",
"You have successfully unblocked :blockable.": "You have successfully unblocked :blockable.",
"You left [:engagement](:engagement_url) by [:projectable](:projectable_url).": "You left [:engagement](:engagement_url) by [:projectable](:projectable_url).",
"You may accept this invitation by clicking the button below:": "You may accept this invitation by clicking the button below:",
"You must agree to the privacy policy.": "You must agree to the privacy policy.",
"You must agree to the terms of service.": "You must agree to the terms of service.",
Expand Down
14 changes: 13 additions & 1 deletion resources/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@
"engagement description (French)": "description de la consultation (français)",
"Engagement estimate has been submitted for your approval": "Le devis pour la consultation a été transmis pour votre approbation",
"engagement format": "format de la consultation",
"Engagement joined": "",
"Engagement materials": "Documents de consultation",
"Engagement meetings": "Réunions de la consultation",
"engagement name": "nom de la consultation",
Expand Down Expand Up @@ -858,6 +859,8 @@
"Leave engagement": "Quitter la consultation",
"Leave organization": "Quitter l’organisation",
"Leave this organization": "Quitter cette organisation",
"Left :engagement": "",
"Left engagement": "",
"Light grey on grey": "Gris clair sur gris",
"Light theme": "Thème clair",
"Link copied!": "Lien copié !",
Expand Down Expand Up @@ -1480,6 +1483,7 @@
"show up on search results for them": "apparaître dans les résultats de recherche",
"Signed language for interpretation": "Langue signée pour l’interprétation",
"signed language for translation": "traduction en langue des signes",
"Signed up for :engagement": "",
"Sign in": "S’identifier",
"Sign language interpretation": "Interprétation en langue des signes",
"Sign language interpretations": "Interprétation en langue des signes",
Expand Down Expand Up @@ -1766,7 +1770,10 @@
"Video": "Vidéo",
"Video recording": "Enregistrement vidéo",
"View": "Afficher",
"View engagement": "",
"View engagement details": "",
"View page": "Voir la page",
"View this engagement at :url.": "",
"Virtual or in-person": "Virtuel ou en personne",
"Virtual – phone call": "Virtuel - appel téléphonique",
"Virtual – web conference": "Virtuel - conférence en ligne",
Expand Down Expand Up @@ -1962,9 +1969,13 @@
"You have joined :invitationable as a :role": "Vous avez rejoint :invitationable en tant que :role",
"You have joined as a :role": "Vous êtes maintenant :role",
"You have joined the team.": "Vous avez rejoint une équipe.",
"You have left :engagement by :projectable": "",
"You have left [:engagement](:engagement_url) by [:projectable](:projectable_url).": "",
"You have not added any engagements yet.": "Vous n’avez pas encore ajouté de consultations.",
"You have not passed the quiz.": "Vous n’avez pas réussi le jeu-questionnaire.",
"You have now completed this course. Your certificate of completion has been sent to your email.": "Vous avez complété avec succès ce sours. Votre certification de réussite vous a été envoyé par courriel.",
"You have signed up for :engagement by :projectable": "",
"You have signed up for [:engagement](:engagement_url) by [:projectable](:projectable_url).": "",
"You have successfully added :notificationable to your list.": "Vous avez ajouté avec succès :notificationable à votre liste.",
"You have successfully added :organization as the Community Organization you are consulting with for this engagement.": "Vous avez ajouté avec succès :organization comme l’organisation communautaire avec laquelle vous travaillez pour cette consultation.",
"You have successfully added the Community Organization you are consulting with for this engagement.": "Vous avez ajouté avec succès l’organisation communautaire avec laquelle vous travaillez pour cette consultation.",
Expand All @@ -1987,6 +1998,7 @@
"You have successfully submitted an estimate request.": "Votre demande de devis a été soumise avec succès.",
"You have successfully unblocked.": "Débloqué avec succès.",
"You have successfully unblocked :blockable.": "Vous avez débloqué :blockable.",
"You left [:engagement](:engagement_url) by [:projectable](:projectable_url).": "",
"You may accept this invitation by clicking the button below:": "Vous pouvez accepter cette invitation en cliquant sur le bouton ci-dessous :",
"You must agree to the privacy policy.": "Vous devez accepter la politique de confidentialité.",
"You must agree to the terms of service.": "Vous devez accepter les conditions de service.",
Expand Down Expand Up @@ -2167,4 +2179,4 @@
"“About your organization” (English)": "« À propos de votre organisation » (en anglais)",
"“About your organization” (French)": "À propos de votre organisation",
"“About your organization” must be provided in either English or French.": "À propos de votre organisation doit être fournis en anglais ou en français."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<x-notification :notification="$notification">
<x-slot name="title">{{ $title }}</x-slot>
<x-slot name="body">{{ $body }}</x-slot>
<x-slot name="actions">
<a class="cta secondary"
href="{{ localized_route('engagements.show', $engagement) }}">{{ __('View engagement') }}</a>
</x-slot>
</x-notification>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<x-notification :notification="$notification">
<x-slot name="title">{{ $title }}</x-slot>
<x-slot name="body">{{ $body }}</x-slot>
<x-slot name="actions">
<a class="cta secondary"
href="{{ localized_route('engagements.show', $engagement) }}">{{ __('View engagement') }}</a>
</x-slot>
</x-notification>
14 changes: 14 additions & 0 deletions resources/views/mail/joined-engagement.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@component('mail::message')
{{
safe_markdown('You have signed up for [:engagement](:engagement_url) by [:projectable](:projectable_url).', [
'engagement' => $engagement->getTranslation('name', locale()),
'engagement_url' => localized_route('engagements.show', $engagement),
'projectable' => $projectable->getTranslation('name', locale()),
'projectable_url' => localized_route($projectable->getRoutePrefix().'.show', $projectable),
])
}}

@component('mail::button', ['url' => localized_route('engagements.show', $engagement)])
{{ __('View engagement details') }}
@endcomponent
@endcomponent
Loading