Merged PR 1956: Destination Info Component

Related work items: #5347
This commit is contained in:
Lorenz Hilpert
2025-09-23 08:07:42 +00:00
committed by Nino Righi
parent 6ab839a529
commit 243b83bd73
28 changed files with 474 additions and 3 deletions

View File

@@ -1,2 +1,3 @@
export * from './lib/services';
export * from './lib/models';
export * from './lib/helpers';
export * from './lib/services';
export * from './lib/models';

View File

@@ -0,0 +1,18 @@
export const OrderType = {
Pickup: 'Abholung',
Delivery: 'Versand',
InStore: 'Rücklage',
} as const;
export type OrderType = (typeof OrderType)[keyof typeof OrderType];
export function getOrderTypeFeature(
features: Record<string, string> = {},
): OrderType | undefined {
const orderType = features['orderType'];
if (orderType && Object.values(OrderType).includes(orderType as OrderType)) {
return orderType as OrderType;
}
return undefined;
}

View File

@@ -0,0 +1 @@
export * from './get-order-type-feature.helper';

View File

@@ -0,0 +1,3 @@
import { AvailabilityDTO } from '@generated/swagger/checkout-api';
export type Availability = AvailabilityDTO;

View File

@@ -0,0 +1,3 @@
import { CheckoutItemDTO } from '@generated/swagger/checkout-api';
export type CheckoutItem = CheckoutItemDTO;

View File

@@ -0,0 +1,3 @@
import { CheckoutDTO } from '@generated/swagger/checkout-api';
export type Checkout = CheckoutDTO;

View File

@@ -0,0 +1,6 @@
import { DestinationDTO } from '@generated/swagger/checkout-api';
import { ShippingTarget } from './shipping-target';
export type Destination = DestinationDTO & {
target: ShippingTarget;
};

View File

@@ -1 +1,8 @@
export * from './query-settings';
export * from './availability';
export * from './checkout-item';
export * from './checkout';
export * from './destination';
export * from './query-settings';
export * from './shipping-address';
export * from './shipping-target';
export * from './shopping-cart-item';

View File

@@ -0,0 +1,3 @@
import { ShippingAddressDTO } from '@generated/swagger/checkout-api';
export type ShippingAddress = ShippingAddressDTO;

View File

@@ -0,0 +1,8 @@
export const ShippingTarget = {
None: 0,
Branch: 1,
Delivery: 2,
} as const;
export type ShippingTarget =
(typeof ShippingTarget)[keyof typeof ShippingTarget];

View File

@@ -0,0 +1,3 @@
import { ShoppingCartItemDTO } from '@generated/swagger/checkout-api';
export type ShoppingCartItem = ShoppingCartItemDTO;

View File

@@ -1,2 +1,3 @@
export * from './lib/destination-info/destination-info.component';
export * from './lib/product-info/product-info-redemption.component';
export * from './lib/stock-info/stock-info.component';

View File

@@ -0,0 +1,3 @@
:host {
@apply flex flex-col items-start gap-2 flex-grow;
}

View File

@@ -0,0 +1,19 @@
<div class="flex items-center gap-2 self-stretch">
<ng-icon
[name]="destinationIcon()"
size="1.5rem"
class="text-neutral-900"
></ng-icon>
<span class="isa-text-body-2-bold text-isa-secondary-900">{{
orderType()
}}</span>
</div>
<div class="text-isa-neutral-600 isa-text-body-2-regular">
@if (displayAddress()) {
{{ branchName() }} |
<shared-inline-address [address]="address()"></shared-inline-address>
} @else if (estimatedDelivery(); as delivery) {
Zustellung zwischen {{ delivery.start | date: 'E, dd.MM.' }} und
{{ delivery.stop | date: 'E, dd.MM.' }}
}
</div>

View File

@@ -0,0 +1,74 @@
import { Component, computed, input } from '@angular/core';
import {
getOrderTypeFeature,
OrderType,
ShoppingCartItem,
} from '@isa/checkout/data-access';
import {
isaDeliveryVersand,
isaDeliveryRuecklage2,
isaDeliveryRuecklage1,
} from '@isa/icons';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { InlineAddressComponent } from '@isa/shared/address';
import { DatePipe } from '@angular/common';
@Component({
selector: 'checkout-destination-info',
templateUrl: './destination-info.component.html',
styleUrls: ['./destination-info.component.css'],
imports: [NgIcon, InlineAddressComponent, DatePipe],
providers: [
provideIcons({
isaDeliveryVersand,
isaDeliveryRuecklage2,
isaDeliveryRuecklage1,
}),
],
})
export class DestinationInfoComponent {
shoppingCartItem =
input.required<
Pick<ShoppingCartItem, 'availability' | 'destination' | 'features'>
>();
orderType = computed(() => {
return getOrderTypeFeature(this.shoppingCartItem().features);
});
destinationIcon = computed(() => {
const orderType = this.orderType();
if (OrderType.Delivery === orderType) {
return 'isaDeliveryVersand';
}
if (OrderType.Pickup === orderType) {
return 'isaDeliveryRuecklage2';
}
if (OrderType.InStore === orderType) {
return 'isaDeliveryRuecklage1';
}
});
displayAddress = computed(() => {
const orderType = this.orderType();
return OrderType.InStore === orderType || OrderType.Pickup === orderType;
});
branchName = computed(() => {
const destination = this.shoppingCartItem().destination;
return destination?.data?.targetBranch?.data?.name;
});
address = computed(() => {
const destination = this.shoppingCartItem().destination;
console.log(destination?.data?.targetBranch?.data?.address);
return destination?.data?.targetBranch?.data?.address;
});
estimatedDelivery = computed(() => {
return this.shoppingCartItem().availability?.estimatedDelivery;
});
}

View File

@@ -0,0 +1,7 @@
# shared-address
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test shared-address` to execute the unit tests.

View File

@@ -0,0 +1,34 @@
const nx = require('@nx/eslint-plugin');
const baseConfig = require('../../../eslint.config.js');
module.exports = [
...baseConfig,
...nx.configs['flat/angular'],
...nx.configs['flat/angular-template'],
{
files: ['**/*.ts'],
rules: {
'@angular-eslint/directive-selector': [
'error',
{
type: 'attribute',
prefix: 'shared',
style: 'camelCase',
},
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: 'shared',
style: 'kebab-case',
},
],
},
},
{
files: ['**/*.html'],
// Override or add rules here
rules: {},
},
];

View File

@@ -0,0 +1,20 @@
{
"name": "shared-address",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/shared/address/src",
"prefix": "shared",
"projectType": "library",
"tags": [],
"targets": {
"test": {
"executor": "@nx/vite:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"reportsDirectory": "../../../coverage/libs/shared/address"
}
},
"lint": {
"executor": "@nx/eslint:lint"
}
}
}

View File

@@ -0,0 +1,2 @@
export * from './lib/inline-address.component';
export * from './lib/types';

View File

@@ -0,0 +1,14 @@
import { Component, input, OnInit } from '@angular/core';
import { Address } from './types';
@Component({
selector: 'shared-inline-address',
template: `
@if (address(); as a) {
{{ a.street }} {{ a.streetNumber }}, {{ a.postalCode }} {{ a.city }}
}
`,
})
export class InlineAddressComponent {
address = input<Address>();
}

View File

@@ -0,0 +1,7 @@
export interface Address {
street?: string;
streetNumber?: string;
postalCode?: string;
city?: string;
country?: string;
}

View File

@@ -0,0 +1,13 @@
import '@angular/compiler';
import '@analogjs/vitest-angular/setup-zone';
import {
BrowserTestingModule,
platformBrowserTesting,
} from '@angular/platform-browser/testing';
import { getTestBed } from '@angular/core/testing';
getTestBed().initTestEnvironment(
BrowserTestingModule,
platformBrowserTesting(),
);

View File

@@ -0,0 +1,30 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"importHelpers": true,
"moduleResolution": "bundler",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"module": "preserve"
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"typeCheckHostBindings": true,
"strictTemplates": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@@ -0,0 +1,27 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": []
},
"exclude": [
"src/**/*.spec.ts",
"src/test-setup.ts",
"jest.config.ts",
"src/**/*.test.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx"
],
"include": ["src/**/*.ts"]
}

View File

@@ -0,0 +1,29 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": [
"vitest/globals",
"vitest/importMeta",
"vite/client",
"node",
"vitest"
]
},
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"files": ["src/test-setup.ts"]
}

View File

@@ -0,0 +1,27 @@
/// <reference types='vitest' />
import { defineConfig } from 'vite';
import angular from '@analogjs/vite-plugin-angular';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../../node_modules/.vite/libs/shared/address',
plugins: [angular(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
// Uncomment this if you are using workers.
// worker: {
// plugins: [ nxViteTsPaths() ],
// },
test: {
watch: false,
globals: true,
environment: 'jsdom',
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
setupFiles: ['src/test-setup.ts'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../../coverage/libs/shared/address',
provider: 'v8' as const,
},
},
}));