Skip to content
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: 3 additions & 1 deletion frontend/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideRouter, withViewTransitions } from '@angular/router';
import { TitleStrategy, provideRouter, withViewTransitions } from '@angular/router';
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
import { providePrimeNG } from 'primeng/config';
import { ConfirmationService, MessageService } from 'primeng/api';
Expand All @@ -8,13 +8,15 @@ import { routes } from './app.routes';
import { authInterceptor } from './core/auth/auth.interceptor';
import { HEBREW_TRANSLATION } from './core/i18n/primeng-hebrew';
import { TalmidonPreset } from './core/theme/talmidon-preset';
import { AppTitleStrategy } from './core/title/app-title.strategy';

export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
// מעבר חלק בין מסכים במקום החלפה חדה; דפדפנים בלי התמיכה מתעלמים בשקט
provideRouter(routes, withViewTransitions()),
provideHttpClient(withFetch(), withInterceptors([authInterceptor])),
{ provide: TitleStrategy, useClass: AppTitleStrategy },
MessageService,
ConfirmationService,
providePrimeNG({
Expand Down
35 changes: 32 additions & 3 deletions frontend/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ export const routes: Routes = [
},
{
path: 'teachers/:id',
title: 'פרופיל מורה',
loadComponent: () =>
import('./features/public/teacher-profile/teacher-profile.component').then(m => m.TeacherProfileComponent)
},
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'login', title: 'התחברות', component: LoginComponent },
{ path: 'register', title: 'הרשמה כמורה', component: RegisterComponent },
{
path: 'forgot-password',
title: 'שחזור סיסמה',
loadComponent: () =>
import('./features/auth/forgot-password/forgot-password.component').then(m => m.ForgotPasswordComponent)
},
{
path: 'set-password',
title: 'קביעת סיסמה',
loadComponent: () => import('./features/auth/set-password/set-password.component').then(m => m.SetPasswordComponent)
},
{
Expand All @@ -38,49 +41,60 @@ export const routes: Routes = [
// מסך ההקמה עצמו מחוץ ל-profileSetupGuard, אחרת הוא היה מפנה אל עצמו בלולאה
{
path: 'setup',
title: 'הקמת הפרופיל',
loadComponent: () =>
import('./features/teacher/profile-setup/profile-setup.component').then(m => m.ProfileSetupComponent)
},
{ path: 'dashboard', component: DashboardComponent },
{ path: 'dashboard', title: 'ראשי', component: DashboardComponent },
{
path: 'students',
title: 'תלמידים',
loadComponent: () => import('./features/students/students-list/students-list.component').then(m => m.StudentsListComponent)
},
{
path: 'students/:id',
title: 'כרטיס תלמיד',
loadComponent: () => import('./features/students/student-detail/student-detail.component').then(m => m.StudentDetailComponent)
},
{
path: 'lessons',
title: 'יומן שיעורים',
loadComponent: () => import('./features/lessons/lessons-list/lessons-list.component').then(m => m.LessonsListComponent)
},
{
path: 'payments',
title: 'תשלומים',
loadComponent: () => import('./features/payments/payments-list/payments-list.component').then(m => m.PaymentsListComponent)
},
{
path: 'reports',
title: 'דוחות',
loadComponent: () => import('./features/reports/reports.component').then(m => m.ReportsComponent)
},
{
path: 'contact-requests',
title: 'פניות',
loadComponent: () =>
import('./features/contact-requests/contact-requests.component').then(m => m.ContactRequestsComponent)
},
{
path: 'messages',
title: 'הודעות',
loadComponent: () => import('./features/messages/messages.component').then(m => m.MessagesComponent)
},
{
path: 'lesson-plan',
title: 'בניית מערך שיעור',
loadComponent: () => import('./features/ai/lesson-plan.component').then(m => m.LessonPlanComponent)
},
{
path: 'profile',
title: 'הגדרות פרופיל',
loadComponent: () => import('./features/teacher/profile/profile.component').then(m => m.TeacherProfileSettingsComponent)
},
{
path: 'account',
title: 'הגדרות חשבון',
loadComponent: () =>
import('./features/teacher/account-settings/account-settings.component').then(m => m.AccountSettingsComponent)
}
Expand All @@ -94,28 +108,34 @@ export const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'dashboard' },
{
path: 'dashboard',
title: 'ראשי',
loadComponent: () =>
import('./features/parent-portal/parent-dashboard/parent-dashboard.component').then(m => m.ParentDashboardComponent)
},
{
path: 'lessons',
title: 'יומן שיעורים',
loadComponent: () => import('./features/parent-portal/parent-lessons/parent-lessons.component').then(m => m.ParentLessonsComponent)
},
{
path: 'notes',
title: 'הערות',
loadComponent: () => import('./features/parent-portal/parent-notes/parent-notes.component').then(m => m.ParentNotesComponent)
},
{
path: 'payments',
title: 'תשלומים',
loadComponent: () => import('./features/parent-portal/parent-payments/parent-payments.component').then(m => m.ParentPaymentsComponent)
},
{
path: 'resources',
title: 'חומרי לימוד',
loadComponent: () =>
import('./features/parent-portal/parent-resources/parent-resources.component').then(m => m.ParentResourcesComponent)
},
{
path: 'messages',
title: 'הודעות',
loadComponent: () =>
import('./features/messages/portal-messages.component').then(m => m.PortalMessagesComponent)
}
Expand All @@ -129,29 +149,35 @@ export const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'dashboard' },
{
path: 'dashboard',
title: 'ראשי',
loadComponent: () =>
import('./features/student-portal/student-dashboard/student-dashboard.component').then(m => m.StudentDashboardComponent)
},
{
path: 'lessons',
title: 'יומן שיעורים',
loadComponent: () => import('./features/student-portal/student-lessons/student-lessons.component').then(m => m.StudentLessonsComponent)
},
{
path: 'notes',
title: 'הערות',
loadComponent: () => import('./features/student-portal/student-notes/student-notes.component').then(m => m.StudentNotesComponent)
},
{
path: 'resources',
title: 'חומרי לימוד',
loadComponent: () =>
import('./features/student-portal/student-resources/student-resources.component').then(m => m.StudentResourcesComponent)
},
{
path: 'games',
title: 'משחקים',
loadComponent: () =>
import('./features/student-portal/games/games.component').then(m => m.StudentGamesComponent)
},
{
path: 'messages',
title: 'הודעות',
loadComponent: () =>
import('./features/messages/portal-messages.component').then(m => m.PortalMessagesComponent)
}
Expand All @@ -165,14 +191,17 @@ export const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'teachers' },
{
path: 'teachers',
title: 'מורות',
loadComponent: () => import('./features/admin/admin-teachers/admin-teachers.component').then(m => m.AdminTeachersComponent)
},
{
path: 'subjects',
title: 'תחומי לימוד',
loadComponent: () => import('./features/admin/admin-subjects/admin-subjects.component').then(m => m.AdminSubjectsComponent)
},
{
path: 'feedback',
title: 'הודעות מהאתר',
loadComponent: () => import('./features/admin/admin-feedback/admin-feedback.component').then(m => m.AdminFeedbackComponent)
}
]
Expand Down
25 changes: 25 additions & 0 deletions frontend/src/app/core/title/app-title.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Injectable, inject } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { RouterStateSnapshot, TitleStrategy } from '@angular/router';

const APP_NAME = 'תלמידון';

/**
* מעדכן את כותרת הדף לפי המסלול.
*
* באפליקציה של עמוד יחיד הכותרת לא מתחלפת מעצמה, וכל המסכים נראו בלשונית
* הדפדפן ובהיסטוריה בשם אחד — "תלמידון". למי שעובדת עם קורא מסך זו גם ההודעה
* היחידה שאומרת "עברת מסך", כי אין טעינה מחדש שתכריז על זה.
*
* הכותרת של כל מסלול זהה לכותרת שרואים על המסך, כדי שלשונית והמסך יאמרו
* אותו דבר.
*/
@Injectable({ providedIn: 'root' })
export class AppTitleStrategy extends TitleStrategy {
private readonly title = inject(Title);

override updateTitle(snapshot: RouterStateSnapshot): void {
const page = this.buildTitle(snapshot);
this.title.setTitle(page ? `${page} · ${APP_NAME}` : APP_NAME);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ <h3 class="m-0">{{ contact.fullName }}</h3>
@if (contact.status !== Status.Closed) {
<p-button label="סגירה" icon="pi pi-times-circle" severity="secondary" [text]="true" size="small" (onClick)="setStatus(contact, Status.Closed)" />
}
<p-button icon="pi pi-trash" severity="danger" [text]="true" size="small" pTooltip="מחיקה" tooltipPosition="top" (onClick)="confirmDelete(contact)" />
<p-button icon="pi pi-trash" severity="danger" [text]="true" size="small" [ariaLabel]="'מחיקת הפנייה של ' + contact.fullName" pTooltip="מחיקה" tooltipPosition="top" (onClick)="confirmDelete(contact)" />
</div>
</p-card>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { CalendarEventsService } from '../calendar-events.service';
import { CalendarEventItem } from '../calendar-events.models';
import { IsraelDatePipe } from '../../../core/i18n/israel-date.pipe';
import { LessonAmountSuggestion, lessonDurationMinutes, suggestLessonAmountDetailed } from '../lesson-pricing.util';
import { RestoreFocusOnCloseDirective } from '../../../shared/a11y/restore-focus.directive';

@Component({
selector: 'app-lessons-list',
Expand All @@ -57,7 +58,7 @@ import { LessonAmountSuggestion, lessonDurationMinutes, suggestLessonAmountDetai
SelectModule,
TagModule,
TextareaModule,
LessonCalendarComponent, PageHeaderComponent, IsraelDatePipe],
LessonCalendarComponent, PageHeaderComponent, IsraelDatePipe, RestoreFocusOnCloseDirective],
templateUrl: './lessons-list.component.html'
})
export class LessonsListComponent implements OnInit {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/app/features/messages/messages.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ConversationComponent } from './conversation.component';
import { MessageAuthor, MessageRecipient, ThreadDetail, ThreadSummary } from './messages.models';
import { MessagesService } from './messages.service';
import { ThreadListComponent } from './thread-list.component';
import { RestoreFocusOnCloseDirective } from '../../shared/a11y/restore-focus.directive';

/** נמען עם התווית המוכנה — p-select מקבל שם שדה, לא פונקציה. */
type RecipientOption = MessageRecipient & { label: string };
Expand All @@ -34,7 +35,7 @@ type RecipientOption = MessageRecipient & { label: string };
PageHeaderComponent,
ThreadListComponent,
ConversationComponent
],
, RestoreFocusOnCloseDirective],
templateUrl: './messages.component.html',
styleUrls: ['./messages.scss', './messages-screen.scss']
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ConversationComponent } from './conversation.component';
import { MessageAuthor, ThreadDetail, ThreadSummary } from './messages.models';
import { MessagesService } from './messages.service';
import { ThreadListComponent } from './thread-list.component';
import { RestoreFocusOnCloseDirective } from '../../shared/a11y/restore-focus.directive';

/**
* תיבת ההודעות של התלמידה ושל ההורה — אותו מסך לשניהם.
Expand All @@ -37,7 +38,7 @@ import { ThreadListComponent } from './thread-list.component';
PageHeaderComponent,
ThreadListComponent,
ConversationComponent
],
, RestoreFocusOnCloseDirective],
templateUrl: './portal-messages.component.html',
styleUrls: ['./messages.scss', './messages-screen.scss']
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
import { MyChild } from '../parent-portal.models';
import { ParentPortalService } from '../parent-portal.service';
import { IsraelDatePipe } from '../../../core/i18n/israel-date.pipe';
import { RestoreFocusOnCloseDirective } from '../../../shared/a11y/restore-focus.directive';

@Component({
selector: 'app-parent-lessons',
Expand All @@ -42,7 +43,7 @@ import { IsraelDatePipe } from '../../../core/i18n/israel-date.pipe';
InputTextModule,
SelectModule,
TagModule,
LessonCalendarComponent, PageHeaderComponent, IsraelDatePipe],
LessonCalendarComponent, PageHeaderComponent, IsraelDatePipe, RestoreFocusOnCloseDirective],
templateUrl: './parent-lessons.component.html'
})
export class ParentLessonsComponent implements OnInit {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@
<p-tag [value]="payment.confirmationSentAt ? 'נשלח' : 'לא נשלח'" [severity]="payment.confirmationSentAt ? 'success' : 'secondary'" />
</td>
<td>
<p-button icon="pi pi-trash" severity="danger" [text]="true" (onClick)="confirmDeletePayment(payment)" />
<p-button icon="pi pi-trash" severity="danger" [text]="true" (onClick)="confirmDeletePayment(payment)" [ariaLabel]="'מחיקת התשלום של ' + payment.parentName + ' מ־' + (payment.paidDate | ilDate: 'dd/MM/yyyy')" />
</td>
</tr>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { LESSON_STATUS_CLASS, LESSON_STATUS_LABELS, LESSON_STATUS_SEVERITY, Less
import { StudentLesson } from '../student-portal.models';
import { StudentPortalService } from '../student-portal.service';
import { IsraelDatePipe } from '../../../core/i18n/israel-date.pipe';
import { RestoreFocusOnCloseDirective } from '../../../shared/a11y/restore-focus.directive';

@Component({
selector: 'app-student-lessons',
Expand All @@ -29,7 +30,7 @@ import { IsraelDatePipe } from '../../../core/i18n/israel-date.pipe';
TagModule,
TextareaModule,
LessonCalendarComponent,
PageHeaderComponent, IsraelDatePipe],
PageHeaderComponent, IsraelDatePipe, RestoreFocusOnCloseDirective],
templateUrl: './student-lessons.component.html'
})
export class StudentLessonsComponent implements OnInit {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ <h3 class="mb-2">הורים מקושרים</h3>
<span>{{ parent.fullName }} · {{ parent.email }}</span>
<div class="flex align-items-center gap-1">
@if (hasWhatsapp(parent.phone)) {
<p-button icon="pi pi-whatsapp" severity="success" [text]="true" (onClick)="openWhatsapp(parent)" pTooltip="שלח וואטסאפ" tooltipPosition="top" />
<p-button icon="pi pi-whatsapp" severity="success" [text]="true" (onClick)="openWhatsapp(parent)" [ariaLabel]="'שליחת וואטסאפ אל ' + parent.fullName" pTooltip="שלח וואטסאפ" tooltipPosition="top" />
}
@if (hasEmail(parent.email)) {
<p-button icon="pi pi-envelope" severity="secondary" [text]="true" (onClick)="openParentEmail(parent)" pTooltip="שלח מייל" tooltipPosition="top" />
<p-button icon="pi pi-envelope" severity="secondary" [text]="true" (onClick)="openParentEmail(parent)" [ariaLabel]="'שליחת מייל אל ' + parent.fullName" pTooltip="שלח מייל" tooltipPosition="top" />
}
<p-button icon="pi pi-times" severity="danger" [text]="true" (onClick)="unlinkParent(parent.id)" />
<p-button icon="pi pi-times" severity="danger" [text]="true" (onClick)="unlinkParent(parent.id)" [ariaLabel]="'ניתוק הקישור אל ' + parent.fullName" pTooltip="ניתוק הקישור" tooltipPosition="top" />
</div>
</li>
}
Expand Down Expand Up @@ -109,8 +109,8 @@ <h3 class="m-0">הערות פדגוגיות</h3>
<div class="flex justify-content-between align-items-start gap-2">
<p class="m-0 flex-1" style="white-space: pre-wrap">{{ note.content }}</p>
<div class="flex gap-1">
<p-button icon="pi pi-pencil" severity="secondary" [text]="true" (onClick)="openEditNoteDialog(note)" />
<p-button icon="pi pi-trash" severity="danger" [text]="true" (onClick)="confirmDeleteNote(note)" />
<p-button icon="pi pi-pencil" severity="secondary" [text]="true" (onClick)="openEditNoteDialog(note)" [ariaLabel]="'עריכת ההערה מ־' + (note.createdAt | ilDate: 'dd/MM/yyyy HH:mm')" />
<p-button icon="pi pi-trash" severity="danger" [text]="true" (onClick)="confirmDeleteNote(note)" [ariaLabel]="'מחיקת ההערה מ־' + (note.createdAt | ilDate: 'dd/MM/yyyy HH:mm')" />
</div>
</div>
<div class="flex gap-2 mt-2 align-items-center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { ResourcesService } from '../../resources/resources.service';
import { ParentSummary, StudentDetail } from '../students.models';
import { StudentsService } from '../students.service';
import { IsraelDatePipe } from '../../../core/i18n/israel-date.pipe';
import { RestoreFocusOnCloseDirective } from '../../../shared/a11y/restore-focus.directive';

@Component({
selector: 'app-student-detail',
Expand All @@ -50,7 +51,7 @@ import { IsraelDatePipe } from '../../../core/i18n/israel-date.pipe';
TextareaModule,
TooltipModule,
EmptyStateComponent,
ResourceListComponent, IsraelDatePipe],
ResourceListComponent, IsraelDatePipe, RestoreFocusOnCloseDirective],
templateUrl: './student-detail.component.html'
})
export class StudentDetailComponent implements OnInit {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
<td>{{ parent.phone || '—' }}</td>
<td>{{ parent.studentCount }}</td>
<td>
<p-button icon="pi pi-pencil" severity="secondary" [text]="true" (onClick)="openEditParentDialog(parent)" />
<p-button icon="pi pi-pencil" severity="secondary" [text]="true" (onClick)="openEditParentDialog(parent)" [ariaLabel]="'עריכת הפרטים של ' + parent.fullName" />
</td>
</tr>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Parent } from '../../parents/parents.models';
import { ParentsService } from '../../parents/parents.service';
import { StudentListItem } from '../students.models';
import { StudentsService } from '../students.service';
import { RestoreFocusOnCloseDirective } from '../../../shared/a11y/restore-focus.directive';

@Component({
selector: 'app-students-list',
Expand All @@ -36,7 +37,7 @@ import { StudentsService } from '../students.service';
SelectModule,
TableModule,
TabsModule,
TagModule, PageHeaderComponent, EmptyStateComponent],
TagModule, PageHeaderComponent, EmptyStateComponent, RestoreFocusOnCloseDirective],
templateUrl: './students-list.component.html'
})
export class StudentsListComponent implements OnInit {
Expand Down
Loading
Loading