delivery
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
<div class="delivery-selector">
|
||||
@if (isDigital) {
|
||||
<div class="delivery-chip delivery-chip--digital">{{ 'cart.digitalDelivery' | translate }}</div>
|
||||
} @else if (options.length > 0) {
|
||||
<label class="delivery-label" [for]="selectId">{{ 'cart.deliveryMethod' | translate }}</label>
|
||||
|
||||
<div class="delivery-control">
|
||||
<select [id]="selectId" [ngModel]="selectedKey" (ngModelChange)="onSelectionChange($event)">
|
||||
@if (required) {
|
||||
<option value="">{{ 'cart.selectDelivery' | translate }}</option>
|
||||
}
|
||||
|
||||
@for (option of options; track trackByOption($index, option)) {
|
||||
<option [value]="optionKey(option)">{{ optionLabel(option) }}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@if (selectedDelivery) {
|
||||
<div class="delivery-meta">
|
||||
@if (selectedDelivery.deliveryPlace) {
|
||||
<span>{{ 'cart.deliveryPlace' | translate }}: {{ selectedDelivery.deliveryPlace }}</span>
|
||||
}
|
||||
@if (selectedDelivery.deliveryTime) {
|
||||
<span>{{ 'cart.deliveryTime' | translate }}: {{ selectedDelivery.deliveryTime }}</span>
|
||||
}
|
||||
<span>
|
||||
{{ 'cart.deliveryLabel' | translate }}:
|
||||
{{ selectedDeliveryTotal | number:'1.2-2' }} {{ currency }}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,81 @@
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.delivery-selector {
|
||||
margin-top: 12px;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #d3dad9;
|
||||
background: #fafbfb;
|
||||
}
|
||||
|
||||
.delivery-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
color: #3f5f5c;
|
||||
}
|
||||
|
||||
.delivery-control select {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #c9d5d3;
|
||||
background: #fff;
|
||||
color: #1f2937;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.delivery-control select:focus {
|
||||
outline: none;
|
||||
border-color: #497671;
|
||||
box-shadow: 0 0 0 3px rgba(73, 118, 113, 0.12);
|
||||
}
|
||||
|
||||
.delivery-meta {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
margin-top: 10px;
|
||||
font-size: 0.82rem;
|
||||
color: #697777;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.delivery-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.delivery-chip--digital {
|
||||
color: #2563eb;
|
||||
background: rgba(37, 99, 235, 0.12);
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-selector {
|
||||
border-color: #d1fae5;
|
||||
background: #f9fffc;
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-label {
|
||||
color: #047857;
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-control select {
|
||||
border-color: #bbf7d0;
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-control select:focus {
|
||||
border-color: #10b981;
|
||||
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.12);
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-meta {
|
||||
color: #4b5563;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CartItem, DeliveryOption } from '../../models';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
|
||||
let nextDeliverySelectorId = 0;
|
||||
|
||||
@Component({
|
||||
selector: 'app-delivery-selector',
|
||||
standalone: true,
|
||||
imports: [FormsModule, DecimalPipe, TranslatePipe],
|
||||
templateUrl: './delivery-selector.component.html',
|
||||
styleUrls: ['./delivery-selector.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DeliverySelectorComponent {
|
||||
@Input({ required: true }) item: CartItem | null = null;
|
||||
|
||||
@Output() selectedDeliveryChange = new EventEmitter<DeliveryOption | null>();
|
||||
|
||||
readonly selectId = `delivery-select-${nextDeliverySelectorId++}`;
|
||||
|
||||
get options(): DeliveryOption[] {
|
||||
return this.item?.deliveryOptions ?? [];
|
||||
}
|
||||
|
||||
get selectedDelivery(): DeliveryOption | null {
|
||||
return this.item?.selectedDelivery ?? null;
|
||||
}
|
||||
|
||||
get currency(): string {
|
||||
return this.item?.currency || 'RUB';
|
||||
}
|
||||
|
||||
get required(): boolean {
|
||||
return this.item?.deliveryMode !== 'digital'
|
||||
&& this.options.length > 0
|
||||
&& this.item?.deliverySelectionRequired !== false;
|
||||
}
|
||||
|
||||
get isDigital(): boolean {
|
||||
return this.item?.deliveryMode === 'digital';
|
||||
}
|
||||
|
||||
get selectedKey(): string {
|
||||
return this.selectedDelivery ? this.optionKey(this.selectedDelivery) : '';
|
||||
}
|
||||
|
||||
get selectedDeliveryTotal(): number {
|
||||
return (this.selectedDelivery?.deliveryPrice ?? 0) * (this.item?.quantity ?? 1);
|
||||
}
|
||||
|
||||
optionKey(option: DeliveryOption): string {
|
||||
return `${option.deliveryPlace}__${option.deliveryTime}__${option.deliveryPrice}`;
|
||||
}
|
||||
|
||||
optionLabel(option: DeliveryOption): string {
|
||||
const details = [option.deliveryPlace, option.deliveryTime].filter(Boolean);
|
||||
details.push(`${option.deliveryPrice.toFixed(2)} ${this.currency}`);
|
||||
return details.join(' • ');
|
||||
}
|
||||
|
||||
trackByOption(index: number, option: DeliveryOption): string {
|
||||
return `${index}-${this.optionKey(option)}`;
|
||||
}
|
||||
|
||||
onSelectionChange(nextKey: string): void {
|
||||
if (!nextKey) {
|
||||
this.selectedDeliveryChange.emit(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedDeliveryChange.emit(
|
||||
this.options.find(option => this.optionKey(option) === nextKey) ?? null
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user