Skip to content

Commit

Permalink
portalicious: payment and registration page review
Browse files Browse the repository at this point in the history
AB#30048 AB#31172
  • Loading branch information
aberonni committed Jan 3, 2025
1 parent ecddaf9 commit 800a584
Show file tree
Hide file tree
Showing 30 changed files with 344 additions and 188 deletions.
8 changes: 2 additions & 6 deletions e2e/portalicious/pages/RegistrationsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ interface ExportExcelFspData {
class RegistrationsPage extends BasePage {
readonly page: Page;
readonly table: TableComponent;
readonly goToProfileOption: Locator;
readonly sendMessageDialogPreview: Locator;
readonly exportButton: Locator;
readonly proceedButton: Locator;
Expand All @@ -110,7 +109,6 @@ class RegistrationsPage extends BasePage {
super(page);
this.page = page;
this.table = new TableComponent(page);
this.goToProfileOption = this.page.getByText('Go to profile');
this.sendMessageDialogPreview = this.page.getByTestId(
'send-message-dialog-preview',
);
Expand Down Expand Up @@ -194,8 +192,7 @@ class RegistrationsPage extends BasePage {
(registrationName && isRequestedFullName) ||
(!registrationName && !isRequestedFullName)
) {
await fullName.click({ button: 'right' });
await this.goToProfileOption.click();
await fullName.getByRole('link').click();
return;
}
}
Expand Down Expand Up @@ -252,8 +249,7 @@ class RegistrationsPage extends BasePage {
const randomIndex = Math.floor(Math.random() * rowCount);
const fullName = await this.table.getCell(randomIndex, 2);

await fullName.click({ button: 'right' });
await this.goToProfileOption.click();
await fullName.getByRole('link').click();
return randomIndex;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ export function getChipDataByTwilioMessageStatus(status: string): ChipData {
switch (messageStatus) {
case MessageStatus.delivered:
case MessageStatus.read:
case MessageStatus.sent:
return {
chipLabel,
chipVariant: 'green',
Expand All @@ -80,6 +79,7 @@ export function getChipDataByTwilioMessageStatus(status: string): ChipData {
chipLabel,
chipVariant: 'red',
};
case MessageStatus.sent:
default:
return {
chipLabel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
@if (projectId()) {
<app-project-menu [projectId]="projectId()!" />
}
<div class="flex-1 px-6 py-8 lg:px-24">
<div class="flex-1 px-6 py-6 lg:px-24">
@if (pageTitle()) {
@let parentTitle = parentPageTitle();
@let parentLink = parentPageLink();

<div class="flex items-start justify-between pb-9 pt-1">
<div class="flex items-center justify-between pb-6 pt-1">
<h1 class="min-w-48">
@if (isPending()) {
<p-skeleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,70 +89,65 @@
</th>
}
@for (column of visibleColumns(); track $index) {
@if (column.field) {
<th
[pSortableColumn]="getColumnSortField(column)"
style="min-width: 14rem"
>
<div class="flex items-center">
<ng-container>{{ column.header }}</ng-container>
@let columnSortField = getColumnSortField(column);
@let columnFilterField = getColumnFilterField(column);
@let columnMatchMode = getColumnMatchMode(column);

@let columnSortField = getColumnSortField(column);
<th
[pSortableColumn]="columnSortField"
style="min-width: 14rem"
>
<div class="flex items-center">
<ng-container>{{ column.header }}</ng-container>

@if (columnSortField) {
<p-sortIcon
[field]="columnSortField"
class="me-0 ms-2 mt-1"
/>
}

@let columnFilterField = getColumnFilterField(column);
@let columnMatchMode = getColumnMatchMode(column);
@if (columnSortField) {
<p-sortIcon
[field]="columnSortField"
class="me-0 ms-2 mt-1"
/>
}

@if (columnFilterField) {
@if (column.type === 'multiselect') {
<p-columnFilter
[field]="columnFilterField"
[matchMode]="columnMatchMode"
display="menu"
[showMatchModes]="false"
[showOperator]="false"
[showAddButton]="false"
@if (columnFilterField) {
@if (column.type === 'multiselect') {
<p-columnFilter
[field]="columnFilterField"
[matchMode]="columnMatchMode"
display="menu"
[showMatchModes]="false"
[showOperator]="false"
[showAddButton]="false"
>
<ng-template
pTemplate="filter"
let-value
let-filter="filterCallback"
>
<ng-template
pTemplate="filter"
let-value
let-filter="filterCallback"
<p-multiSelect
[ngModel]="value"
[options]="column.options"
(onChange)="filter($event.value)"
[optionLabel]="'label'"
[optionValue]="'value'"
placeholder="Choose option(s)"
i18n-placeholder
>
<p-multiSelect
[ngModel]="value"
[options]="column.options"
(onChange)="filter($event.value)"
[optionLabel]="'label'"
[optionValue]="'value'"
placeholder="Choose option(s)"
i18n-placeholder
>
</p-multiSelect>
</ng-template>
</p-columnFilter>
} @else {
<p-columnFilter
[type]="getColumnType(column)"
[field]="columnFilterField"
display="menu"
[matchMode]="columnMatchMode"
[showMatchModes]="false"
[showOperator]="false"
[showAddButton]="false"
/>
}
</p-multiSelect>
</ng-template>
</p-columnFilter>
} @else {
<p-columnFilter
[type]="getColumnType(column)"
[field]="columnFilterField"
display="menu"
[matchMode]="columnMatchMode"
[showMatchModes]="false"
[showOperator]="false"
[showAddButton]="false"
/>
}
</div>
</th>
} @else {
<th style="min-width: 14rem">{{ column.header }}</th>
}
}
</div>
</th>
}
@if (contextMenuItems()) {
<!-- Extra column for the ellipsis button -->
Expand Down Expand Up @@ -282,29 +277,46 @@
<tr data-testid="query-table-empty">
<td [attr.colspan]="totalColumnCount()">
<div class="w-full py-6 text-center">
<i class="pi pi-filter mb-5 inline text-xl"></i>

<p
i18n
class="mb-2 font-bold"
>
No results found
</p>
@if (isFiltered()) {
<i class="pi pi-filter mb-5 inline text-xl"></i>

<p
i18n
class="mb-8"
>
There are no records that match the selected filters, clear some or
all filters to continue.
</p>
<p
i18n
class="mb-2 font-bold"
>
No results found
</p>
<p
i18n
class="mb-8"
>
There are no records that match the selected filters, clear some
or all filters to continue.
</p>

<p-button
label="Clear all filters"
i18n-label="@@table-clear-filters"
link
(click)="clearAllFilters()"
/>
<p-button
label="Clear all filters"
i18n-label="@@table-clear-filters"
link
(click)="clearAllFilters()"
/>
} @else {
@let emptyMessageTemplate = emptyMessage();
@if (emptyMessageTemplate) {
<ng-container
[ngTemplateOutlet]="emptyMessageTemplate"
></ng-container>
} @else {
<i class="pi pi-exclamation-circle mb-3 inline text-xl"></i>
<p
i18n
class="mb-2 font-bold"
>
No results
</p>
<p i18n>There are no records to display.</p>
}
}
</div>
</td>
</tr>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { DatePipe, NgComponentOutlet } from '@angular/common';
import { DatePipe, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
computed,
contentChild,
effect,
inject,
input,
LOCALE_ID,
model,
output,
signal,
TemplateRef,
Type,
viewChild,
} from '@angular/core';
Expand Down Expand Up @@ -109,6 +111,7 @@ export type QueryTableSelectionEvent<TData> = { selectAll: true } | TData[];
CheckboxModule,
QueryTableGlobalSearchComponent,
QueryTableColumnManagementComponent,
NgTemplateOutlet,
],
providers: [ToastService],
templateUrl: './query-table.component.html',
Expand Down Expand Up @@ -137,6 +140,8 @@ export class QueryTableComponent<TData extends { id: PropertyKey }, TContext> {
readonly updateContextMenuItem = output<TData>();
readonly updatePaginateQuery = output<PaginateQuery>();

readonly emptyMessage =
contentChild<TemplateRef<unknown>>('tableEmptyMessage');
readonly table = viewChild.required<Table>('table');
readonly contextMenu = viewChild<Menu>('contextMenu');
readonly extraOptionsMenu = viewChild<Menu>('extraOptionsMenu');
Expand Down Expand Up @@ -399,12 +404,12 @@ export class QueryTableComponent<TData extends { id: PropertyKey }, TContext> {
if ('selectAll' in selection && !this.serverSideFiltering()) {
const filteredValue = this.table().filteredValue;

if (!filteredValue) {
this.toastService.showGenericError();
return;
if (this.table().filteredValue) {
selection = [...(filteredValue as TData[])];
} else {
// no filters are applied, so we can select all items
selection = [...this.items()];
}

selection = [...(filteredValue as TData[])];
}

if (Array.isArray(selection) && selection.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
i18n
class="font-semibold"
>
You are about to add a note to {{ registrationName() }}'s profile.
You are about to add a note to {{ registration.data()?.name }}'s profile.
</p>
<p
i18n
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import {
} from '@angular/forms';

import { injectMutation } from '@tanstack/angular-query-experimental';
import { injectQuery } from '@tanstack/angular-query-experimental';
import { TextareaModule } from 'primeng/textarea';

import { FormSidebarComponent } from '~/components/form/form-sidebar.component';
import { FormFieldWrapperComponent } from '~/components/form-field-wrapper/form-field-wrapper.component';
import { ProjectApiService } from '~/domains/project/project.api.service';
import { RegistrationApiService } from '~/domains/registration/registration.api.service';
import { ToastService } from '~/services/toast.service';
import {
generateFieldErrors,
Expand All @@ -41,12 +43,20 @@ type AddNoteFormGroup = (typeof AddNoteFormComponent)['prototype']['formGroup'];
})
export class AddNoteFormComponent {
private projectApiService = inject(ProjectApiService);
private registrationApiService = inject(RegistrationApiService);
private toastService = inject(ToastService);

formVisible = model.required<boolean>();
projectId = input.required<string>();
registrationReferenceId = input.required<string>();
registrationName = input<null | string>();
registrationId = input.required<string>();

project = injectQuery(this.projectApiService.getProject(this.projectId));
registration = injectQuery(
this.registrationApiService.getRegistrationById(
this.projectId,
this.registrationId,
),
);

formGroup = new FormGroup({
note: new FormControl('', {
Expand All @@ -61,17 +71,29 @@ export class AddNoteFormComponent {
});

addNoteMutation = injectMutation(() => ({
mutationFn: ({ note }: ReturnType<AddNoteFormGroup['getRawValue']>) =>
this.projectApiService.addRegistrationNote({
mutationFn: ({ note }: ReturnType<AddNoteFormGroup['getRawValue']>) => {
const registrationReferenceId = this.registration.data()?.referenceId;

if (!registrationReferenceId) {
// Should never happen but makes TS happy
throw new Error('Registration reference ID is missing');
}

return this.projectApiService.addRegistrationNote({
projectId: this.projectId,
registrationReferenceId: this.registrationReferenceId,
registrationReferenceId,
note,
}),
});
},
onSuccess: () => {
this.formGroup.reset();
this.toastService.showToast({
detail: $localize`Note successfully added.`,
});
void this.registrationApiService.invalidateCache(
this.projectId,
this.registrationId,
);
this.formVisible.set(false);
},
}));
Expand Down
Loading

0 comments on commit 800a584

Please sign in to comment.