This commit is contained in:
sdarbinyan
2026-06-21 23:13:01 +04:00
parent 1b2a5af2be
commit 3b802b7c7b
13 changed files with 510 additions and 33 deletions

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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
);
}
}