Browse Source

feat(admin-ui): Improve styling of order/customer history timeline

Michael Bromley 2 years ago
parent
commit
aeebbdd7bd

+ 64 - 23
packages/admin-ui/src/lib/core/src/shared/components/timeline-entry/timeline-entry.component.scss

@@ -1,3 +1,4 @@
+@import 'variables';
 
 :host {
     display: block;
@@ -5,19 +6,32 @@
     &:first-of-type {
         .timeline {
             &:before {
-                border-left-color: var(--color-timeline-thread);
+                border-left-color: var(--color-weight-200);
             }
         }
+
         .entry-body {
             max-height: initial;
+            @media screen and (min-width: $breakpoint-small) {
+                flex-direction: column;
+            }
+        }
+        .featured-entry {
+            width: 100%;
         }
     }
 }
+
 .entry {
     display: flex;
+
+    &:not(.collapsed):hover {
+        background-color: var(--color-table-row-hover-bg);
+    }
 }
+
 .timeline {
-    border-inline-start: 2px solid var(--color-timeline-thread);
+    border-inline-start: 2px solid var(--color-weight-200);
     padding-bottom: 8px;
     position: relative;
 
@@ -27,21 +41,23 @@
         width: 2px;
         height: 32px;
         left: -2px;
-        border-inline-start: 2px solid var(--color-timeline-thread);
+        border-inline-start: 2px solid var(--color-weight-200);
     }
+
     &:after {
         content: '';
         display: block;
         border-radius: 50%;
         width: 8px;
         height: 8px;
-        background-color: var(--color-component-bg-200);
-        border: 1px solid var(--color-component-border-300);
+        background-color: var(--color-weight-100);
+        border: 1px solid var(--color-weight-300);
         position: absolute;
         left: -5px;
-        top: 32px;
+        top: 42%;
         transition: top 0.2s;
         cursor: pointer;
+        outline: 2px solid var(--color-card-bg);
     }
 
     .custom-icon {
@@ -49,24 +65,29 @@
         width: 32px;
         height: 32px;
         left: -17px;
-        top: 32px;
+        top: 30%;
         align-items: center;
         justify-content: center;
         border-radius: 50%;
         color: var(--color-primary-700);
-        background-color: var(--color-component-bg-100);
-        border: 1px solid var(--color-component-border-200);
+        background-color: var(--color-weight-100);
+        border: 1px solid var(--color-weight-200);
+        outline: 7px solid var(--color-card-bg);
+        padding: 6px;
         display: none;
     }
 }
+
 .entry.has-custom-icon {
     .timeline:after {
         display: none;
     }
+
     .custom-icon {
         display: flex;
     }
 }
+
 .entry.last {
     .timeline {
         border-left-color: transparent;
@@ -74,8 +95,9 @@
 }
 
 .entry-body {
+    font-size: var(--font-size-xs);
     flex: 1;
-    padding-top: 24px;
+    padding: 16px 0;
     padding-inline-start: 12px;
     line-height: 16px;
     margin-inline-start: 12px;
@@ -83,14 +105,26 @@
     overflow: visible;
     max-height: 100px;
     transition: max-height 0.2s, padding-top 0.2s, opacity 0.2s 0.2s;
+    @media screen and (min-width: $breakpoint-small) {
+        display: flex;
+        gap: var(--space-unit);
+        flex-direction: row-reverse;
+        justify-content: space-between;
+        align-items: center;
+        padding-inline-end: var(--space-unit);
+    }
 }
 
 .featured-entry ::ng-deep {
     .title {
         color: var(--color-text-100);
-        font-size: 16px;
+        font-size: var(--font-size-sm);
         line-height: 26px;
+        display: flex;
+        align-items: center;
+        gap: var(--space-unit);
     }
+
     .note-text {
         color: var(--color-text-100);
         white-space: pre-wrap;
@@ -99,26 +133,27 @@
 
 .detail {
     display: flex;
+    gap: 12px;
     color: var(--color-text-300);
-    font-size: 12px;
-    .time {
-    }
-    .name {
-        margin-inline-start: 12px;
+    font-size: var(--font-size-xs);
+    @media screen and (min-width: $breakpoint-small) {
+        flex-direction: row-reverse;
     }
 }
 
-
 .muted {
-    .timeline, .timeline .custom-icon {
+    .timeline,
+    .timeline .custom-icon {
         color: var(--color-text-300);
     }
 }
 
 .success {
-    .timeline, .timeline .custom-icon {
+    .timeline,
+    .timeline .custom-icon {
         color: var(--color-success-700);
     }
+
     .timeline:after {
         background-color: var(--color-success-200);
         border: 1px solid var(--color-success-400);
@@ -126,9 +161,11 @@
 }
 
 .error {
-    .timeline, .timeline .custom-icon {
+    .timeline,
+    .timeline .custom-icon {
         color: var(--color-error-700);
     }
+
     .timeline:after {
         background-color: var(--color-error-200);
         border: 1px solid var(--color-error-400);
@@ -136,12 +173,14 @@
 }
 
 .warning {
-    .timeline, .timeline .custom-icon {
+    .timeline,
+    .timeline .custom-icon {
         color: var(--color-warning-700);
     }
+
     .timeline:after {
         background-color: var(--color-warning-200);
-        border: 1px solid var(--color-warning-400);
+        border: 1px solid var(--color-warning-600);
     }
 }
 
@@ -150,11 +189,13 @@
         max-height: 0;
         overflow: hidden;
         opacity: 0;
-        padding-top: 0;
+        padding: 0;
     }
+
     .timeline {
         border-left-color: transparent;
     }
+
     .timeline:after {
         top: 0;
     }

+ 1 - 1
packages/admin-ui/src/lib/order/src/components/order-detail/order-detail.component.scss

@@ -14,5 +14,5 @@
 }
 
 vdr-order-payment-card + vdr-order-payment-card {
-    margin-top: var(--space-unit);
+    margin-top: calc(var(--space-unit) * 2);
 }

+ 47 - 19
packages/admin-ui/src/lib/order/src/components/order-history/order-history.component.html

@@ -48,7 +48,7 @@
                         <ng-template [ngIf]="entry.data.to !== 'Cancelled' && entry.data.to !== 'Delivered'">
                             {{
                                 'order.history-order-transition'
-                                    | translate: { from: entry.data.from, to: entry.data.to }
+                                    | translate : { from: entry.data.from, to: entry.data.to }
                             }}
                         </ng-template>
                     </ng-container>
@@ -59,7 +59,7 @@
                         <ng-container *ngIf="getModification(entry.data.modificationId) as modification">
                             {{ 'order.modify-order-price-difference' | translate }}:
                             <strong>{{
-                                modification.priceChange | localeCurrency: order.currencyCode
+                                modification.priceChange | localeCurrency : order.currencyCode
                             }}</strong>
                             <vdr-chip colorType="success" *ngIf="modification.isSettled">{{
                                 'order.modification-settled' | translate
@@ -80,13 +80,17 @@
                             <div class="title">
                                 {{ 'order.history-payment-settled' | translate }}
                             </div>
-                            {{ 'order.transaction-id' | translate }}: {{ getPayment(entry)?.transactionId }}
-                            <vdr-history-entry-detail *ngIf="getPayment(entry) as payment">
-                                <vdr-payment-detail
-                                    [payment]="payment"
-                                    [currencyCode]="order.currencyCode"
-                                ></vdr-payment-detail>
-                            </vdr-history-entry-detail>
+                            <div class="flex items-center">
+                                <vdr-chip *ngIf="getPayment(entry) as payment" class="mr-1">{{
+                                    payment.amount | localeCurrency : order.currencyCode
+                                }}</vdr-chip>
+                                <vdr-history-entry-detail *ngIf="getPayment(entry) as payment">
+                                    <vdr-payment-detail
+                                        [payment]="payment"
+                                        [currencyCode]="order.currencyCode"
+                                    ></vdr-payment-detail>
+                                </vdr-history-entry-detail>
+                            </div>
                         </ng-container>
                         <ng-template #regularPaymentTransition>
                             {{
@@ -101,18 +105,42 @@
                         </ng-template>
                     </ng-container>
                     <ng-container *ngSwitchCase="type.ORDER_REFUND_TRANSITION">
-                        {{
-                            'order.history-refund-transition'
-                                | translate
-                                    : { from: entry.data.from, to: entry.data.to, id: entry.data.refundId }
-                        }}
+                        <ng-container *ngIf="entry.data.to === 'Settled'; else regularRefundTransition">
+                            <ng-container *ngIf="getRefund(entry) as refund">
+                                <div class="title">{{ 'order.refund' | translate }} #{{ refund.id }}</div>
+                                <div class="flex items-center">
+                                    <vdr-chip colorType="warning" class="mr-1">{{
+                                        refund.total | localeCurrency : order.currencyCode
+                                    }}</vdr-chip>
+                                    <vdr-history-entry-detail>
+                                        <vdr-labeled-data [label]="'order.cancellation-reason' | translate">
+                                            {{ entry.data.reason }}
+                                        </vdr-labeled-data>
+                                        <vdr-labeled-data [label]="'order.contents' | translate">
+                                            <vdr-simple-item-list [items]="getCancelledItems(refund.lines)"></vdr-simple-item-list>
+                                        </vdr-labeled-data>
+                                    </vdr-history-entry-detail>
+                                </div>
+                            </ng-container>
+                        </ng-container>
+                        <ng-template #regularRefundTransition>
+                            {{
+                                'order.history-refund-transition'
+                                    | translate
+                                        : {
+                                              from: entry.data.from,
+                                              to: entry.data.to,
+                                              id: entry.data.refundId
+                                          }
+                            }}
+                        </ng-template>
                     </ng-container>
                     <ng-container *ngSwitchCase="type.ORDER_CANCELLATION">
                         {{
                             'order.history-items-cancelled'
-                                | translate: { count: getCancelledQuantity(entry) }
+                                | translate : { count: getCancelledQuantity(entry) }
                         }}
-                        <vdr-history-entry-detail *ngIf="getCancelledItems(entry) as items">
+                        <vdr-history-entry-detail *ngIf="getCancelledItems(entry.data.lines) as items">
                             <vdr-labeled-data [label]="'order.cancellation-reason' | translate">
                                 {{ entry.data.reason }}
                             </vdr-labeled-data>
@@ -149,7 +177,7 @@
                         <ng-container *ngIf="entry.data.to !== 'Delivered' && entry.data.to !== 'Shipped'">
                             {{
                                 'order.history-fulfillment-transition'
-                                    | translate: { from: entry.data.from, to: entry.data.to }
+                                    | translate : { from: entry.data.from, to: entry.data.to }
                             }}
                         </ng-container>
                         <vdr-history-entry-detail *ngIf="getFulfillment(entry) as fulfillment">
@@ -172,8 +200,8 @@
                             </div>
                             <div class="flex-spacer"></div>
                             <vdr-dropdown>
-                                <button class="icon-button" vdrDropdownTrigger>
-                                    <clr-icon shape="ellipsis-vertical"></clr-icon>
+                                <button class="button-small ml-1" vdrDropdownTrigger>
+                                    <clr-icon shape="ellipsis-vertical" size="12"></clr-icon>
                                 </button>
                                 <vdr-dropdown-menu vdrPosition="bottom-right">
                                     <button

+ 23 - 3
packages/admin-ui/src/lib/order/src/components/order-history/order-history.component.ts

@@ -51,7 +51,7 @@ export class OrderHistoryComponent {
             }
         }
         if (entry.type === HistoryEntryType.ORDER_CANCELLATION) {
-            return 'error';
+            return 'warning';
         }
         if (entry.type === HistoryEntryType.ORDER_REFUND_TRANSITION) {
             return 'warning';
@@ -73,6 +73,11 @@ export class OrderHistoryComponent {
                 return 'credit-card';
             }
         }
+        if (entry.type === HistoryEntryType.ORDER_REFUND_TRANSITION) {
+            if (entry.data.to === 'Settled') {
+                return 'credit-card';
+            }
+        }
         if (entry.type === HistoryEntryType.ORDER_NOTE) {
             return 'note';
         }
@@ -98,6 +103,8 @@ export class OrderHistoryComponent {
                     entry.data.to === 'Settled'
                 );
             }
+            case HistoryEntryType.ORDER_REFUND_TRANSITION:
+                return entry.data.to === 'Settled';
             case HistoryEntryType.ORDER_PAYMENT_TRANSITION:
                 return entry.data.to === 'Settled' || entry.data.to === 'Cancelled';
             case HistoryEntryType.ORDER_FULFILLMENT_TRANSITION:
@@ -130,13 +137,26 @@ export class OrderHistoryComponent {
         }
     }
 
+    getRefund(
+        entry: TimelineHistoryEntry,
+    ): NonNullable<OrderDetailFragment['payments']>[number]['refunds'][number] | undefined {
+        if (entry.type === HistoryEntryType.ORDER_REFUND_TRANSITION && this.order.payments) {
+            const allRefunds = this.order.payments.reduce(
+                (refunds, payment) => refunds.concat(payment.refunds),
+                [] as NonNullable<OrderDetailFragment['payments']>[number]['refunds'],
+            );
+            return allRefunds.find(r => r.id === entry.data.refundId);
+        }
+    }
+
     getCancelledQuantity(entry: TimelineHistoryEntry): number {
         return entry.data.lines.reduce((total, line) => total + line.quantity, 0);
     }
 
-    getCancelledItems(entry: TimelineHistoryEntry): Array<{ name: string; quantity: number }> {
+    getCancelledItems(
+        cancellationLines: Array<{ orderLineId: string; quantity: number }>,
+    ): Array<{ name: string; quantity: number }> {
         const itemMap = new Map<string, number>();
-        const cancellationLines: Array<{ orderLineId: string; quantity: number }> = entry.data.lines;
         for (const line of this.order.lines) {
             const cancellationLine = cancellationLines.find(l => l.orderLineId === line.id);
             if (cancellationLine) {

+ 1 - 1
packages/admin-ui/src/lib/order/src/components/order-payment-card/order-payment-card.component.html

@@ -2,7 +2,7 @@
     <div class="card-header payment-header">
         <div>
             {{ 'order.payment' | translate }}
-            <ng-container *ngIf="payment.transactionId">#{{ payment.transactionId }}</ng-container>
+            <ng-container *ngIf="payment.amount">{{ payment.amount | localeCurrency : currencyCode }}</ng-container>
         </div>
         <div class="payment-state">
             <vdr-payment-state-label [state]="payment.state"></vdr-payment-state-label>

+ 1 - 2
packages/admin-ui/src/lib/order/src/components/order-payment-card/order-payment-card.component.scss

@@ -20,6 +20,5 @@
 }
 
 .refund-wrapper {
-    //margin-left: calc(var(--space-unit) * 2);
-    //border-left: 2px solid var(--color-grey-300);
+    font-size: var(--font-size-xs);
 }

+ 9 - 0
packages/admin-ui/src/lib/order/src/components/refund-detail/refund-detail.component.html

@@ -0,0 +1,9 @@
+<vdr-labeled-data [label]="'order.amount' | translate">
+    {{ refund.total | localeCurrency: currencyCode }}
+</vdr-labeled-data>
+<vdr-labeled-data *ngIf="refund.transactionId" [label]="'order.transaction-id' | translate">
+    {{ refund.transactionId }}
+</vdr-labeled-data>
+<vdr-labeled-data [label]="'order.payment-metadata' | translate">
+    <vdr-object-tree [value]="refund.metadata"></vdr-object-tree>
+</vdr-labeled-data>

+ 1 - 0
packages/admin-ui/src/lib/order/src/components/refund-detail/refund-detail.component.scss

@@ -0,0 +1 @@
+@import "variables";

+ 13 - 0
packages/admin-ui/src/lib/order/src/components/refund-detail/refund-detail.component.ts

@@ -0,0 +1,13 @@
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { CurrencyCode, OrderDetailFragment } from '@vendure/admin-ui/core';
+
+@Component({
+    selector: 'vdr-refund-detail',
+    templateUrl: './refund-detail.component.html',
+    styleUrls: ['./refund-detail.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class RefundDetailComponent {
+    @Input() refund: NonNullable<OrderDetailFragment['payments']>[number]['refunds'][number];
+    @Input() currencyCode: CurrencyCode;
+}

+ 4 - 0
packages/admin-ui/src/lib/static/styles/global/_utilities.scss

@@ -12,6 +12,10 @@
     justify-content: center;
 }
 
+.flex.items-center {
+    align-items: center;
+}
+
 .flex.wrap {
     flex-wrap: wrap;
 }

+ 0 - 1
packages/admin-ui/src/lib/static/styles/theme/dark.scss

@@ -80,7 +80,6 @@
     --color-icon-button-hover: var(--color-primary-200);
     --color-form-input-bg: var(--color-weight-150);
     --color-form-input-focus: var(--color-primary-500);
-    --color-timeline-thread: var(--color-primary-700);
 
     --color-json-editor-background-color: var(--color-grey-600);
     --color-json-editor-text: var(--color-grey-100);

+ 1 - 2
packages/admin-ui/src/lib/static/styles/theme/default.scss

@@ -155,9 +155,8 @@
     --color-icon-button-hover: var(--color-primary-600);
     --color-form-input-bg: white;
     --color-form-input-focus: var(--color-primary-100);
-    --color-timeline-thread: var(--color-primary-100);
 
-    --color-chip-warning-border: var(--color-warning-300);
+    --color-chip-warning-border: var(--color-warning-500);
     --color-chip-warning-text: var(--color-warning-800);
     --color-chip-warning-bg: var(--color-warning-150);
     --color-chip-success-border: var(--color-success-200);