Repository navigation
Added email service - #115
Conversation
WalkthroughThis PR introduces a new email sending feature to the admin panel. It adds a navigation link, a new route, a component for the email form UI, and a service to handle email requests to the backend API. Integration includes module declarations and routing configuration. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant SendEmailPageComponent
participant AdminEmailService
participant ApiService
participant Backend as Backend API
User->>SendEmailPageComponent: Submit email form
activate SendEmailPageComponent
SendEmailPageComponent->>SendEmailPageComponent: Validate form (isFormValid)
alt Form Invalid
SendEmailPageComponent->>User: Display error alert
else Form Valid
SendEmailPageComponent->>SendEmailPageComponent: Set isSending = true
SendEmailPageComponent->>AdminEmailService: sendEmail(emailRequest)
activate AdminEmailService
AdminEmailService->>ApiService: post("/api/admin/emails/send", request)
activate ApiService
ApiService->>Backend: POST /api/admin/emails/send
activate Backend
Backend-->>ApiService: SendCustomEmailResponse
deactivate Backend
ApiService-->>AdminEmailService: Observable<SendCustomEmailResponse>
deactivate ApiService
AdminEmailService-->>SendEmailPageComponent: Observable response
deactivate AdminEmailService
SendEmailPageComponent->>SendEmailPageComponent: Set isSending = false
alt Response Success
SendEmailPageComponent->>User: Display success alert
else Response Error
SendEmailPageComponent->>User: Display error message
end
end
deactivate SendEmailPageComponent
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@src/app/modules/admin/components/tools/send-email-page/send-email-page.component.ts`:
- Around line 31-55: The sendEmail() method currently sends raw
this.emailRequest which may include trailing spaces or empty cc values; before
calling adminEmailService.sendEmail, normalize address fields by trimming
strings (to, from, subject, body, and cc entries) and if cc is empty after
trimming, remove the cc property or set it to undefined so it is omitted from
the payload; update sendEmail() to build a sanitized payload (or overwrite
this.emailRequest) and then pass that sanitized object to
adminEmailService.sendEmail(...), keeping the existing isFormValid() and error
handling intact.
🧹 Nitpick comments (4)
src/app/services/admin-email.service.ts (1)
18-26: Consider usingprovidedInor simplify the URL construction.Two minor observations:
The
apiUrlproperty is defined but only used with string concatenation. Consider simplifying to a constant or using it directly.Per Angular best practices, consider using
@Injectable({ providedIn: 'root' })for tree-shakable services, though module-level provision inAdminModuleis also valid for admin-scoped services.♻️ Optional: Simplify URL and add error handling
`@Injectable`() export class AdminEmailService { - private readonly apiUrl = "/api/admin/emails/"; + private readonly sendEmailUrl = "/api/admin/emails/send"; constructor(private readonly api: ApiService) {} sendEmail(request: SendCustomEmailRequest): Observable<SendCustomEmailResponse> { - return this.api.post<SendCustomEmailResponse>(this.apiUrl + "send", request); + return this.api.post<SendCustomEmailResponse>(this.sendEmailUrl, request); } }src/app/modules/admin/components/tools/send-email-page/send-email-page.component.html (3)
9-68: Consider using Angular's form validation for better UX.The form uses HTML5
requiredattributes but lacks Angular form validation feedback. Users don't see validation errors before submission.Consider wrapping in a
<form>element with template-driven or reactive form validation to display inline error messages.♻️ Example: Add form validation feedback
- <div class="mb-3"> - <label for="fromEmail" class="form-label">From <span class="text-danger">*</span></label> - <input - type="email" - id="fromEmail" - [(ngModel)]="emailRequest.from" - class="form-control" - placeholder="sender@yourdomain.com" - required - /> + <div class="mb-3"> + <label for="fromEmail" class="form-label">From <span class="text-danger">*</span></label> + <input + type="email" + id="fromEmail" + [(ngModel)]="emailRequest.from" + `#fromEmail`="ngModel" + class="form-control" + [class.is-invalid]="fromEmail.invalid && fromEmail.touched" + placeholder="sender@yourdomain.com" + required + /> + <div class="invalid-feedback" *ngIf="fromEmail.invalid && fromEmail.touched"> + Valid email address is required + </div>
70-83: Method call in template binding may impact performance.
isFormValid()is called on every change detection cycle. For simple validation this is acceptable, but consider caching the result in a getter or using Angular's built-in form validation state.Based on coding guidelines for Angular templates, you might also consider using the newer
@ifcontrol flow syntax available in Angular 17+:- <span *ngIf="isSending"> + `@if` (isSending) { + <span> <span class="spinner-border spinner-border-sm me-2" role="status"></span> Sending... - </span> - <span *ngIf="!isSending">Send Email</span> + </span> + } `@else` { + <span>Send Email</span> + }
77-79: Consider adding aria-label to the spinner for screen readers.The spinner has
role="status"which is good, but adding anaria-labelwould provide better context for screen reader users.- <span class="spinner-border spinner-border-sm me-2" role="status"></span> + <span class="spinner-border spinner-border-sm me-2" role="status" aria-label="Sending email"></span>
| sendEmail(): void { | ||
| if (!this.isFormValid()) { | ||
| this.alertService.error("Please fill in all required fields"); | ||
| return; | ||
| } | ||
|
|
||
| this.isSending = true; | ||
|
|
||
| this.adminEmailService | ||
| .sendEmail(this.emailRequest) | ||
| .pipe(untilDestroyed(this)) | ||
| .subscribe({ | ||
| next: (response) => { | ||
| this.isSending = false; | ||
| if (response.success) { | ||
| this.alertService.success(response.message); | ||
| } else { | ||
| this.alertService.error(response.message); | ||
| } | ||
| }, | ||
| error: (err) => { | ||
| this.isSending = false; | ||
| this.alertService.error("Failed to send email: " + (err.message || "Unknown error")); | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Normalize address fields before sending (validation/payload mismatch).
isFormValid() trims inputs, but sendEmail() submits raw strings. Trailing spaces (or an empty cc) can pass validation yet be rejected by the backend. Consider trimming address fields and omitting cc when blank before sending.
✅ Suggested fix
sendEmail(): void {
if (!this.isFormValid()) {
this.alertService.error("Please fill in all required fields");
return;
}
this.isSending = true;
+ const cc = this.emailRequest.cc?.trim();
+ const request: SendCustomEmailRequest = {
+ to: this.emailRequest.to.trim(),
+ from: this.emailRequest.from.trim(),
+ subject: this.emailRequest.subject.trim(),
+ htmlBody: this.emailRequest.htmlBody,
+ ...(cc ? { cc } : {}),
+ };
this.adminEmailService
- .sendEmail(this.emailRequest)
+ .sendEmail(request)
.pipe(untilDestroyed(this))
.subscribe({🤖 Prompt for AI Agents
In
`@src/app/modules/admin/components/tools/send-email-page/send-email-page.component.ts`
around lines 31 - 55, The sendEmail() method currently sends raw
this.emailRequest which may include trailing spaces or empty cc values; before
calling adminEmailService.sendEmail, normalize address fields by trimming
strings (to, from, subject, body, and cc entries) and if cc is empty after
trimming, remove the cc property or set it to undefined so it is omitted from
the payload; update sendEmail() to build a sanitized payload (or overwrite
this.emailRequest) and then pass that sanitized object to
adminEmailService.sendEmail(...), keeping the existing isFormValid() and error
handling intact.
Summary by CodeRabbit
New Features
✏️ Tip: You can customize this high-level summary in your review settings.