mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged PR 1969: Reward Shopping Cart Implementation with Navigation State Management and Shipping Address Integration
1. Reward Shopping Cart Implementation - New shopping cart with quantity control and availability checking - Responsive shopping cart item component with improved CSS styling - Shipping address integration in cart - Customer reward card and billing/shipping address components 2. Navigation State Management Library (@isa/core/navigation) - New library with type-safe navigation context service (373 lines) - Navigation state service (287 lines) for temporary state between routes - Comprehensive test coverage (668 + 227 lines of tests) - Documentation (792 lines in README.md) - Replaces query parameters for passing temporary navigation context 3. CRM Shipping Address Services - New ShippingAddressService with fetching and validation - CustomerShippingAddressResource and CustomerShippingAddressesResource - Zod schemas for data validation 4. Additional Improvements - Enhanced searchbox accessibility with ARIA support - Availability data access rework for better fetching/mapping - Storybook tooltip variant support - Vitest JUnit and Cobertura reporting configuration Related work items: #5382, #5383, #5384
This commit is contained in:
committed by
Nino Righi
parent
f15848d5c0
commit
596ae1da1b
@@ -1,3 +1,7 @@
|
||||
:host {
|
||||
@apply flex flex-col items-start gap-2 flex-grow;
|
||||
}
|
||||
|
||||
.address-container {
|
||||
@apply line-clamp-2 break-words text-ellipsis;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,18 @@
|
||||
orderType()
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="text-isa-neutral-600 isa-text-body-2-regular">
|
||||
<div class="text-isa-neutral-600 isa-text-body-2-regular address-container">
|
||||
@if (displayAddress()) {
|
||||
{{ branchName() }} |
|
||||
{{ name() }} |
|
||||
<shared-inline-address [address]="address()"></shared-inline-address>
|
||||
} @else if (estimatedDelivery()) {
|
||||
Zustellung zwischen {{ estimatedDelivery().start | date: 'E, dd.MM.' }} und
|
||||
{{ estimatedDelivery().stop | date: 'E, dd.MM.' }}
|
||||
} @else {
|
||||
@if (estimatedDelivery(); as delivery) {
|
||||
@if (delivery.stop) {
|
||||
Zustellung zwischen {{ delivery.start | date: 'E, dd.MM.' }} und
|
||||
{{ delivery.stop | date: 'E, dd.MM.' }}
|
||||
} @else {
|
||||
Zustellung voraussichtlich am {{ delivery.start | date: 'E, dd.MM.' }}
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
OrderType,
|
||||
ShoppingCartItem,
|
||||
} from '@isa/checkout/data-access';
|
||||
import { SelectedCustomerShippingAddressResource } from '@isa/crm/data-access';
|
||||
import {
|
||||
isaDeliveryVersand,
|
||||
isaDeliveryRuecklage2,
|
||||
@@ -34,10 +35,12 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
isaDeliveryRuecklage1,
|
||||
}),
|
||||
BranchResource,
|
||||
SelectedCustomerShippingAddressResource,
|
||||
],
|
||||
})
|
||||
export class DestinationInfoComponent {
|
||||
#branchResource = inject(BranchResource);
|
||||
#shippingAddressResource = inject(SelectedCustomerShippingAddressResource);
|
||||
|
||||
underline = input<boolean, unknown>(false, {
|
||||
transform: coerceBooleanProperty,
|
||||
@@ -75,7 +78,7 @@ export class DestinationInfoComponent {
|
||||
return (
|
||||
OrderType.InStore === orderType ||
|
||||
OrderType.Pickup === orderType ||
|
||||
OrderType.B2BShipping
|
||||
OrderType.B2BShipping === orderType
|
||||
);
|
||||
});
|
||||
|
||||
@@ -96,16 +99,30 @@ export class DestinationInfoComponent {
|
||||
}
|
||||
});
|
||||
|
||||
branchName = computed(() => {
|
||||
name = computed(() => {
|
||||
const orderType = this.orderType();
|
||||
if (
|
||||
OrderType.Delivery === orderType ||
|
||||
OrderType.B2BShipping === orderType ||
|
||||
OrderType.DigitalShipping === orderType
|
||||
) {
|
||||
const shippingAddress = this.#shippingAddressResource.resource.value();
|
||||
return `${shippingAddress?.firstName || ''} ${shippingAddress?.lastName || ''}`.trim();
|
||||
}
|
||||
|
||||
return this.branch()?.name || 'Filiale nicht gefunden';
|
||||
});
|
||||
|
||||
address = computed(() => {
|
||||
const orderType = this.orderType();
|
||||
|
||||
if (OrderType.B2BShipping === orderType) {
|
||||
// B2B shipping doesn't use branch address
|
||||
return undefined;
|
||||
if (
|
||||
OrderType.Delivery === orderType ||
|
||||
OrderType.B2BShipping === orderType ||
|
||||
OrderType.DigitalShipping === orderType
|
||||
) {
|
||||
const shippingAddress = this.#shippingAddressResource.resource.value();
|
||||
return shippingAddress?.address || undefined;
|
||||
}
|
||||
|
||||
const destination = this.shoppingCartItem().destination;
|
||||
@@ -113,6 +130,18 @@ export class DestinationInfoComponent {
|
||||
});
|
||||
|
||||
estimatedDelivery = computed(() => {
|
||||
return this.shoppingCartItem().availability?.estimatedDelivery;
|
||||
const availability = this.shoppingCartItem().availability;
|
||||
const estimatedDelivery = availability?.estimatedDelivery;
|
||||
const estimatedShippingDate = availability?.estimatedShippingDate;
|
||||
|
||||
if (estimatedDelivery?.start && estimatedDelivery?.stop) {
|
||||
return { start: estimatedDelivery.start, stop: estimatedDelivery.stop };
|
||||
}
|
||||
|
||||
if (estimatedShippingDate) {
|
||||
return { start: estimatedShippingDate, stop: null };
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@let prd = item().product;
|
||||
@let rPoints = points();
|
||||
@if (prd) {
|
||||
<div class="grid grid-cols-[auto,1fr] gap-6">
|
||||
<div class="grid grid-cols-[auto,1fr] gap-6 items-start">
|
||||
<div>
|
||||
<img
|
||||
sharedProductRouterLink
|
||||
@@ -13,7 +13,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 flex-col justify-between gap-1">
|
||||
<div class="flex flex-1 flex-col gap-1">
|
||||
<div class="isa-text-body-2-bold">{{ prd.contributors }}</div>
|
||||
<div
|
||||
[class.isa-text-body-2-regular]="orientation() === 'horizontal'"
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-1 flex-col justify-between gap-1"
|
||||
class="flex flex-1 flex-col gap-2"
|
||||
[class.ml-20]="orientation() === 'vertical'"
|
||||
>
|
||||
<shared-product-format
|
||||
@@ -36,8 +36,11 @@
|
||||
[formatDetail]="prd.formatDetail"
|
||||
[formatDetailsBold]="true"
|
||||
></shared-product-format>
|
||||
<div class="isa-text-body-2-regular text-neutral-600">
|
||||
{{ prd.manufacturer }} | {{ prd.ean }}
|
||||
<div
|
||||
class="flex items-center gap-1 isa-text-body-2-regular text-neutral-600"
|
||||
>
|
||||
<span class="truncate">{{ prd.manufacturer }}</span>
|
||||
<span class="shrink-0">| {{ prd.ean }}</span>
|
||||
</div>
|
||||
<div class="isa-text-body-2-regular text-neutral-600">
|
||||
{{ prd.publicationDate | date: 'dd. MMMM yyyy' }}
|
||||
|
||||
Reference in New Issue
Block a user