Procházet zdrojové kódy

feat(admin-ui): Updated order modification screen with improved UX

Michael Bromley před 2 roky
rodič
revize
ac4c762b02
25 změnil soubory, kde provedl 557 přidání a 548 odebrání
  1. 50 50
      packages/admin-ui/i18n-coverage.json
  2. 4 2
      packages/admin-ui/src/lib/order/src/components/coupon-code-selector/coupon-code-selector.component.html
  3. 300 375
      packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.html
  4. 10 0
      packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.scss
  5. 154 82
      packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.ts
  6. 1 1
      packages/admin-ui/src/lib/order/src/order.module.ts
  7. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/ar.json
  8. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/cs.json
  9. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/de.json
  10. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/en.json
  11. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/es.json
  12. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/fa.json
  13. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/fr.json
  14. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/he.json
  15. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/hr.json
  16. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/it.json
  17. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/nb.json
  18. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/ne.json
  19. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/pl.json
  20. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json
  21. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json
  22. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/ru.json
  23. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/uk.json
  24. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json
  25. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

+ 50 - 50
packages/admin-ui/i18n-coverage.json

@@ -1,101 +1,101 @@
 {
-  "generatedOn": "2024-01-17T15:22:24.662Z",
-  "lastCommit": "5263c2d4e66ca1a87a9f1d36c53f6f8fc2ae48dc",
+  "generatedOn": "2024-01-19T11:46:08.674Z",
+  "lastCommit": "fc1f6490bddbc225b4824007088596372fb9958f",
   "translationStatus": {
     "ar": {
-      "tokenCount": 764,
-      "translatedCount": 759,
-      "percentage": 99
+      "tokenCount": 769,
+      "translatedCount": 766,
+      "percentage": 100
     },
     "cs": {
-      "tokenCount": 764,
-      "translatedCount": 570,
+      "tokenCount": 769,
+      "translatedCount": 578,
       "percentage": 75
     },
     "de": {
-      "tokenCount": 764,
-      "translatedCount": 759,
-      "percentage": 99
+      "tokenCount": 769,
+      "translatedCount": 766,
+      "percentage": 100
     },
     "en": {
-      "tokenCount": 764,
-      "translatedCount": 763,
+      "tokenCount": 769,
+      "translatedCount": 768,
       "percentage": 100
     },
     "es": {
-      "tokenCount": 764,
-      "translatedCount": 759,
-      "percentage": 99
+      "tokenCount": 769,
+      "translatedCount": 766,
+      "percentage": 100
     },
     "fa": {
-      "tokenCount": 764,
-      "translatedCount": 759,
-      "percentage": 99
+      "tokenCount": 769,
+      "translatedCount": 766,
+      "percentage": 100
     },
     "fr": {
-      "tokenCount": 764,
-      "translatedCount": 756,
+      "tokenCount": 769,
+      "translatedCount": 764,
       "percentage": 99
     },
     "he": {
-      "tokenCount": 764,
-      "translatedCount": 759,
-      "percentage": 99
+      "tokenCount": 769,
+      "translatedCount": 766,
+      "percentage": 100
     },
     "hr": {
-      "tokenCount": 764,
-      "translatedCount": 758,
+      "tokenCount": 769,
+      "translatedCount": 765,
       "percentage": 99
     },
     "it": {
-      "tokenCount": 764,
-      "translatedCount": 759,
-      "percentage": 99
+      "tokenCount": 769,
+      "translatedCount": 766,
+      "percentage": 100
     },
     "nb": {
-      "tokenCount": 764,
-      "translatedCount": 756,
+      "tokenCount": 769,
+      "translatedCount": 763,
       "percentage": 99
     },
     "ne": {
-      "tokenCount": 764,
-      "translatedCount": 748,
+      "tokenCount": 769,
+      "translatedCount": 755,
       "percentage": 98
     },
     "pl": {
-      "tokenCount": 764,
-      "translatedCount": 398,
-      "percentage": 52
+      "tokenCount": 769,
+      "translatedCount": 408,
+      "percentage": 53
     },
     "pt_BR": {
-      "tokenCount": 764,
-      "translatedCount": 758,
+      "tokenCount": 769,
+      "translatedCount": 765,
       "percentage": 99
     },
     "pt_PT": {
-      "tokenCount": 764,
-      "translatedCount": 606,
-      "percentage": 79
+      "tokenCount": 769,
+      "translatedCount": 613,
+      "percentage": 80
     },
     "ru": {
-      "tokenCount": 764,
-      "translatedCount": 759,
-      "percentage": 99
+      "tokenCount": 769,
+      "translatedCount": 766,
+      "percentage": 100
     },
     "uk": {
-      "tokenCount": 764,
-      "translatedCount": 594,
+      "tokenCount": 769,
+      "translatedCount": 601,
       "percentage": 78
     },
     "zh_Hans": {
-      "tokenCount": 764,
-      "translatedCount": 539,
+      "tokenCount": 769,
+      "translatedCount": 548,
       "percentage": 71
     },
     "zh_Hant": {
-      "tokenCount": 764,
-      "translatedCount": 385,
-      "percentage": 50
+      "tokenCount": 769,
+      "translatedCount": 395,
+      "percentage": 51
     }
   }
 }

+ 4 - 2
packages/admin-ui/src/lib/order/src/components/coupon-code-selector/coupon-code-selector.component.html

@@ -14,7 +14,9 @@
     (remove)="removeCouponCode.emit($event.value?.code)"
 >
     <ng-template ng-option-tmp let-item="item">
-        <vdr-chip>{{ item.code }}</vdr-chip>
-        {{ item.promotionName }}
+        <div class="flex items-center">
+            <vdr-chip class="mr-1">{{ item.code }}</vdr-chip>
+            <span>{{ item.promotionName }}</span>
+        </div>
     </ng-template>
 </ng-select>

+ 300 - 375
packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.html

@@ -1,9 +1,7 @@
 <vdr-page-block>
     <vdr-action-bar *ngIf="entity$ | async as order">
         <vdr-ab-left>
-            <div class="flex clr-align-items-center">
-                <vdr-order-state-label [state]="order.state"></vdr-order-state-label>
-            </div>
+            <div class="flex clr-align-items-center"></div>
         </vdr-ab-left>
 
         <vdr-ab-right>
@@ -14,384 +12,311 @@
     </vdr-action-bar>
 </vdr-page-block>
 
-<vdr-page-block>
-    <div *ngIf="entity$ | async as order">
-        <div class="clr-row">
-            <div class="clr-col-lg-8">
-                <table class="order-table table">
-                    <thead>
-                        <tr>
-                            <th></th>
-                            <th>{{ 'order.product-name' | translate }}</th>
-                            <th>{{ 'order.product-sku' | translate }}</th>
-                            <th>{{ 'order.unit-price' | translate }}</th>
-                            <th>{{ 'order.quantity' | translate }}</th>
-                            <th *ngIf="orderLineCustomFields.length">
-                                {{ 'common.custom-fields' | translate }}
-                            </th>
-                            <th>{{ 'order.total' | translate }}</th>
-                        </tr>
-                    </thead>
-                    <tbody>
-                        <tr
-                            *ngFor="let line of order.lines; let i = index"
-                            class="order-line"
-                            [class.is-cancelled]="line.quantity === 0"
-                            [class.modified]="isLineModified(line)"
-                        >
-                            <td class="align-middle thumb">
-                                <img
-                                    *ngIf="line.featuredAsset"
-                                    [src]="line.featuredAsset | assetPreview : 'tiny'"
-                                />
-                            </td>
-                            <td class="align-middle name">{{ line.productVariant.name }}</td>
-                            <td class="align-middle sku">{{ line.productVariant.sku }}</td>
-                            <td class="align-middle unit-price">
-                                {{ line.unitPriceWithTax | localeCurrency : order.currencyCode }}
-                                <div class="net-price" [title]="'order.net-price' | translate">
-                                    {{ line.unitPrice | localeCurrency : order.currencyCode }}
-                                </div>
-                            </td>
-                            <td class="align-middle quantity">
-                                <input
-                                    type="number"
-                                    min="0"
-                                    [value]="line.quantity"
-                                    (input)="updateLineQuantity(line, $event.target.value)"
-                                />
-                                <vdr-line-refunds
-                                    [line]="line"
-                                    [payments]="order.payments"
-                                ></vdr-line-refunds>
-                                <vdr-line-fulfillment
-                                    [line]="line"
-                                    [allOrderFulfillments]="order.fulfillments"
-                                    [orderState]="order.state"
-                                ></vdr-line-fulfillment>
-                            </td>
-                            <td
-                                *ngIf="orderLineCustomFields.length"
-                                class="order-line-custom-field align-middle"
-                            >
-                                <vdr-tabbed-custom-fields
-                                    entityName="OrderLine"
-                                    [customFields]="orderLineCustomFields"
-                                    [customFieldsFormGroup]="orderLineCustomFieldsFormArray.get([i])"
-                                    [compact]="true"
-                                ></vdr-tabbed-custom-fields>
-                            </td>
-                            <td class="align-middle total">
-                                {{ line.linePriceWithTax | localeCurrency : order.currencyCode }}
-                                <div class="net-price" [title]="'order.net-price' | translate">
-                                    {{ line.linePrice | localeCurrency : order.currencyCode }}
-                                </div>
-                            </td>
-                        </tr>
-                        <tr
-                            *ngFor="
-                                let addedLine of addedLines;
-                                trackBy: trackByProductVariantId;
-                                let i = index
-                            "
-                            class="modified"
-                        >
-                            <td class="align-middle thumb">
-                                <img
-                                    *ngIf="addedLine.productAsset"
-                                    [src]="addedLine.productAsset | assetPreview : 'tiny'"
-                                />
-                            </td>
-                            <td class="align-middle name">{{ addedLine.productVariantName }}</td>
-                            <td class="align-middle sku">{{ addedLine.sku }}</td>
-                            <td class="align-middle unit-price">
-                                {{ addedLine.priceWithTax | localeCurrency : order.currencyCode }}
-                                <div class="net-price" [title]="'order.net-price' | translate">
-                                    {{ addedLine.price | localeCurrency : order.currencyCode }}
-                                </div>
-                            </td>
-                            <td class="align-middle quantity">
-                                <input
-                                    type="number"
-                                    min="0"
-                                    [value]="addedLine.quantity"
-                                    (input)="updateAddedItemQuantity(addedLine, $event.target.value)"
-                                />
-                                <button class="icon-button" (click)="removeAddedItem(i)">
-                                    <clr-icon shape="trash"></clr-icon>
-                                </button>
-                            </td>
-                            <td
-                                *ngIf="orderLineCustomFields.length"
-                                class="order-line-custom-field align-middle"
-                            >
-                                <ng-container *ngFor="let customField of orderLineCustomFields">
-                                    <vdr-custom-field-control
-                                        [customField]="customField"
-                                        [customFieldsFormGroup]="addItemCustomFieldsFormArray.get([i])"
-                                        entityName="OrderLine"
-                                        [compact]="true"
-                                    ></vdr-custom-field-control>
-                                </ng-container>
-                            </td>
-                            <td class="align-middle total">
-                                {{
-                                    (addedLine.priceWithTax * addedLine.quantity) / 100
-                                        | currency : order.currencyCode
-                                }}
-                                <div class="net-price" [title]="'order.net-price' | translate">
-                                    {{
-                                        (addedLine.price * addedLine.quantity) / 100
-                                            | currency : order.currencyCode
-                                    }}
-                                </div>
-                            </td>
-                        </tr>
-                        <tr class="surcharge" *ngFor="let surcharge of order.surcharges">
-                            <td class="align-middle name left" colspan="2">{{ surcharge.description }}</td>
-                            <td class="align-middle sku">{{ surcharge.sku }}</td>
-                            <td class="align-middle"></td>
-                            <td></td>
-                            <td *ngIf="orderLineCustomFields.length"></td>
-                            <td class="align-middle total">
-                                {{ surcharge.priceWithTax | localeCurrency : order.currencyCode }}
-                                <div class="net-price" [title]="'order.net-price' | translate">
-                                    {{ surcharge.price | localeCurrency : order.currencyCode }}
-                                </div>
-                            </td>
-                        </tr>
-                        <tr
-                            class="surcharge modified"
-                            *ngFor="let surcharge of modifyOrderInput.surcharges; let i = index"
-                        >
-                            <td class="align-middle name left" colspan="2">
-                                {{ surcharge.description }}
-                                <button class="icon-button" (click)="removeSurcharge(i)">
-                                    <clr-icon shape="trash"></clr-icon>
-                                </button>
-                            </td>
-                            <td class="align-middle sku">{{ surcharge.sku }}</td>
-                            <td class="align-middle"></td>
-                            <td></td>
-                            <td *ngIf="orderLineCustomFields.length"></td>
-                            <td class="align-middle total">
-                                <ng-container *ngIf="getSurchargePrices(surcharge) as surchargePrice">
-                                    {{ surchargePrice.priceWithTax | localeCurrency : order.currencyCode }}
-                                    <div class="net-price" [title]="'order.net-price' | translate">
-                                        {{ surchargePrice.price | localeCurrency : order.currencyCode }}
-                                    </div>
-                                </ng-container>
-                            </td>
-                        </tr>
-                        <tr class="shipping">
-                            <td class="left clr-align-middle">{{ 'order.shipping' | translate }}</td>
-                            <td class="clr-align-middle">
-                                {{ order.shippingLines[0]?.shippingMethod?.name }}
-                            </td>
-                            <td colspan="3"></td>
-                            <td *ngIf="orderLineCustomFields.length"></td>
-                            <td class="clr-align-middle">
-                                {{ order.shippingWithTax | localeCurrency : order.currencyCode }}
-                                <div class="net-price" [title]="'order.net-price' | translate">
-                                    {{ order.shipping | localeCurrency : order.currencyCode }}
-                                </div>
-                            </td>
-                        </tr>
-                    </tbody>
-                </table>
+<vdr-page-detail-layout *ngIf="entity$ | async as order">
+    <vdr-page-detail-sidebar>
+        <vdr-card [title]="'order.modification-summary' | translate">
+            <vdr-labeled-data
+                *ngIf="modifyOrderInput.adjustOrderLines?.length"
+                [label]="
+                    'order.modification-adjusting-lines'
+                        | translate : { count: modifyOrderInput.adjustOrderLines?.length }
+                "
+            >
+                <div *ngFor="let line of adjustedLines" class="mb-1">
+                    {{ line }}
+                </div>
+            </vdr-labeled-data>
+            <vdr-labeled-data
+                *ngIf="modifyOrderInput.addItems?.length"
+                [label]="
+                    'order.modification-adding-items'
+                        | translate : { count: modifyOrderInput.addItems?.length }
+                "
+            >
+                <div *ngFor="let item of addedLines">
+                    {{ item.productVariant.name }} x {{ item.quantity }}
+                </div>
+            </vdr-labeled-data>
+            <vdr-labeled-data
+                *ngIf="modifyOrderInput.surcharges?.length"
+                [label]="
+                    'order.modification-adding-surcharges'
+                        | translate : { count: modifyOrderInput.surcharges?.length }
+                "
+            >
+                <div *ngFor="let surcharge of modifyOrderInput.surcharges" class="mb-1">
+                    {{ surcharge.description }}: {{ surcharge.price | localeCurrency : order.currencyCode }}
+                </div>
+            </vdr-labeled-data>
+            <vdr-labeled-data
+                *ngIf="shippingAddressForm.dirty"
+                [label]="'order.modification-updating-shipping-address' | translate"
+            >
+                {{ getModifiedFields(shippingAddressForm) }}
+            </vdr-labeled-data>
+            <vdr-labeled-data
+                *ngIf="billingAddressForm.dirty"
+                [label]="'order.modification-updating-billing-address' | translate"
+            >
+                {{ getModifiedFields(billingAddressForm) }}
+            </vdr-labeled-data>
+            <vdr-labeled-data *ngIf="couponCodesControl.dirty" [label]="'order.set-coupon-codes' | translate">
+                <div *ngFor="let change of couponCodeChanges" class="mb-1">{{ change }}</div>
+            </vdr-labeled-data>
 
-                <h4 class="mb-2">{{ 'order.modifications' | translate }}</h4>
-                <clr-accordion>
-                    <clr-accordion-panel>
-                        <clr-accordion-title>{{ 'order.add-item-to-order' | translate }}</clr-accordion-title>
-                        <clr-accordion-content *clrIfExpanded>
-                            <vdr-product-variant-selector
-                                class="mb-4"
-                                (productSelected)="addItemSelectedVariant = $event"
-                            >
-                            </vdr-product-variant-selector>
-                            <div *ngIf="addItemSelectedVariant" class="flex mb-4">
-                                <img
-                                    *ngIf="addItemSelectedVariant.productAsset as asset"
-                                    [src]="asset | assetPreview : 'tiny'"
-                                    class="mr-4 add-item-thumb"
-                                />
-                                <div>
-                                    <strong class="mr-4">{{
-                                        addItemSelectedVariant.productVariantName
-                                    }}</strong>
-                                    <small>{{ addItemSelectedVariant.sku }}</small>
-                                    <div>
-                                        {{
-                                            getSelectedItemPrice(addItemSelectedVariant)
-                                                | localeCurrency : order.currencyCode
-                                        }}
-                                    </div>
-                                </div>
-                            </div>
-                            <ng-container *ngFor="let customField of orderLineCustomFields">
-                                <vdr-custom-field-control
-                                    [readonly]="!addItemSelectedVariant"
-                                    [customField]="customField"
-                                    [customFieldsFormGroup]="addItemCustomFieldsForm"
-                                    entityName="OrderLine"
-                                    [compact]="true"
-                                ></vdr-custom-field-control>
-                            </ng-container>
-                            <button
-                                class="btn btn-secondary"
-                                [disabled]="!addItemSelectedVariant || addItemCustomFieldsForm.invalid"
-                                (click)="addItemToOrder(addItemSelectedVariant)"
-                            >
-                                {{ 'order.add-item-to-order' | translate }}
-                            </button>
-                        </clr-accordion-content>
-                    </clr-accordion-panel>
-                    <clr-accordion-panel>
-                        <clr-accordion-title>{{ 'order.set-coupon-codes' | translate }}</clr-accordion-title>
-                        <clr-accordion-content *clrIfExpanded>
-                            <vdr-coupon-code-selector
-                                [control]="couponCodesControl"
-                            ></vdr-coupon-code-selector>
-                        </clr-accordion-content>
-                    </clr-accordion-panel>
+            <div *ngIf="!hasModifications()" class="no-modifications">
+                {{ 'order.no-modifications-made' | translate }}
+            </div>
 
-                    <clr-accordion-panel>
-                        <clr-accordion-title>{{ 'order.add-surcharge' | translate }}</clr-accordion-title>
-                        <clr-accordion-content *clrIfExpanded>
-                            <form [formGroup]="surchargeForm" (submit)="addSurcharge(surchargeForm.value)">
-                                <vdr-form-field [label]="'common.description' | translate" for="description"
-                                    ><input id="description" type="text" formControlName="description"
-                                /></vdr-form-field>
-                                <vdr-form-field [label]="'order.product-sku' | translate" for="sku"
-                                    ><input id="sku" type="text" formControlName="sku"
-                                /></vdr-form-field>
-                                <vdr-form-field [label]="'common.price' | translate" for="price">
-                                    <vdr-currency-input
-                                        [currencyCode]="order.currencyCode"
-                                        id="price"
-                                        formControlName="price"
-                                    ></vdr-currency-input>
-                                </vdr-form-field>
-                                <vdr-form-field
-                                    [label]="
-                                        'catalog.price-includes-tax-at'
-                                            | translate : { rate: surchargeForm.get('taxRate')?.value }
-                                    "
-                                    for="priceIncludesTax"
-                                    ><input
-                                        id="priceIncludesTax"
-                                        type="checkbox"
-                                        clrCheckbox
-                                        formControlName="priceIncludesTax"
-                                /></vdr-form-field>
-                                <vdr-form-field [label]="'order.tax-rate' | translate" for="taxRate">
-                                    <vdr-affixed-input suffix="%"
-                                        ><input
-                                            id="taxRate"
-                                            type="number"
-                                            min="0"
-                                            max="100"
-                                            formControlName="taxRate"
-                                    /></vdr-affixed-input>
-                                </vdr-form-field>
-                                <vdr-form-field
-                                    [label]="'order.tax-description' | translate"
-                                    for="taxDescription"
-                                    ><input id="taxDescription" type="text" formControlName="taxDescription"
-                                /></vdr-form-field>
-                                <button
-                                    class="btn btn-secondary"
-                                    [disabled]="
-                                        surchargeForm.invalid ||
-                                        surchargeForm.pristine ||
-                                        surchargeForm.get('price')?.value === 0
-                                    "
-                                >
-                                    {{ 'order.add-surcharge' | translate }}
-                                </button>
-                            </form>
-                        </clr-accordion-content>
-                    </clr-accordion-panel>
-                    <clr-accordion-panel>
-                        <clr-accordion-title>{{
-                            'order.edit-shipping-address' | translate
-                        }}</clr-accordion-title>
-                        <clr-accordion-content *clrIfExpanded>
-                            <vdr-address-form
-                                [formGroup]="shippingAddressForm"
-                                [availableCountries]="availableCountries$ | async"
-                                [customFields]="addressCustomFields"
-                            ></vdr-address-form>
-                        </clr-accordion-content>
-                    </clr-accordion-panel>
-                    <clr-accordion-panel>
-                        <clr-accordion-title>{{
-                            'order.edit-billing-address' | translate
-                        }}</clr-accordion-title>
-                        <clr-accordion-content *clrIfExpanded>
-                            <vdr-address-form
-                                [formGroup]="billingAddressForm"
-                                [availableCountries]="availableCountries$ | async"
-                                [customFields]="addressCustomFields"
-                            ></vdr-address-form>
-                        </clr-accordion-content>
-                    </clr-accordion-panel>
-                </clr-accordion>
+            <div *ngIf="hasModifications()" class="summary-controls">
+                <vdr-form-field [label]="'order.note' | translate">
+                    <textarea [(ngModel)]="note" name="note" required></textarea>
+                </vdr-form-field>
+                <label class="flex items-center">
+                    <input type="checkbox" [(ngModel)]="recalculateShipping" />
+                    <div class="ml-1">{{ 'order.modification-recalculate-shipping' | translate }}</div>
+                </label>
+                <button
+                    class="btn btn-primary mt-2"
+                    (click)="previewAndModify(order)"
+                >
+                    {{ 'order.preview-changes' | translate }}
+                </button>
             </div>
-            <div class="clr-col-lg-4 order-cards">
-                <div class="card">
-                    <div class="card-header">
-                        {{ 'order.modification-summary' | translate }}
-                    </div>
-                    <div class="card-block">
-                        <ul>
-                            <li *ngIf="modifyOrderInput.addItems?.length">
-                                {{
-                                    'order.modification-adding-items'
-                                        | translate : { count: modifyOrderInput.addItems?.length }
-                                }}
-                            </li>
-                            <li *ngIf="modifyOrderInput.adjustOrderLines?.length">
-                                {{
-                                    'order.modification-adjusting-lines'
-                                        | translate : { count: modifyOrderInput.adjustOrderLines?.length }
-                                }}
-                            </li>
-                            <li *ngIf="modifyOrderInput.surcharges?.length">
-                                {{
-                                    'order.modification-adding-surcharges'
-                                        | translate : { count: modifyOrderInput.surcharges?.length }
-                                }}
-                            </li>
-                            <li *ngIf="shippingAddressForm.dirty">
-                                {{ 'order.modification-updating-shipping-address' | translate }}
-                            </li>
-                            <li *ngIf="billingAddressForm.dirty">
-                                {{ 'order.modification-updating-billing-address' | translate }}
-                            </li>
-                        </ul>
-                    </div>
-                    <div class="card-block">
-                        <label class="clr-control-label">{{ 'order.note' | translate }}</label>
-                        <textarea [(ngModel)]="note" name="note" clrTextarea required></textarea>
-                        <clr-checkbox-wrapper class="">
-                            <input type="checkbox" clrCheckbox [(ngModel)]="recalculateShipping" />
-                            <label>{{ 'order.modification-recalculate-shipping' | translate }}</label>
-                        </clr-checkbox-wrapper>
-                    </div>
-                    <div class="card-footer">
+        </vdr-card>
+        <vdr-card [title]="'order.set-coupon-codes' | translate">
+            <vdr-coupon-code-selector [control]="couponCodesControl"></vdr-coupon-code-selector>
+        </vdr-card>
+        <vdr-card [title]="'order.shipping-address' | translate">
+            <ng-template vdrCardControls>
+                <button
+                    class="button-small"
+                    [title]="'order.edit-shipping-address' | translate"
+                    (click)="editingShippingAddress = !editingShippingAddress"
+                >
+                    <clr-icon shape="edit"></clr-icon>
+                </button>
+            </ng-template>
+            <vdr-formatted-address
+                *ngIf="!editingShippingAddress"
+                [address]="shippingAddressForm.value"
+            ></vdr-formatted-address>
+            <vdr-address-form
+                *ngIf="editingShippingAddress"
+                [formGroup]="shippingAddressForm"
+                [availableCountries]="availableCountries$ | async"
+                [customFields]="addressCustomFields"
+            ></vdr-address-form>
+        </vdr-card>
+        <vdr-card [title]="'order.billing-address' | translate">
+            <ng-template vdrCardControls>
+                <button
+                    class="button-small"
+                    [title]="'order.edit-billing-address' | translate"
+                    (click)="editingBillingAddress = !editingBillingAddress"
+                >
+                    <clr-icon shape="edit"></clr-icon>
+                </button>
+            </ng-template>
+            <vdr-formatted-address
+                *ngIf="!editingBillingAddress"
+                [address]="billingAddressForm.value"
+            ></vdr-formatted-address>
+            <vdr-address-form
+                *ngIf="editingBillingAddress"
+                [formGroup]="billingAddressForm"
+                [availableCountries]="availableCountries$ | async"
+                [customFields]="addressCustomFields"
+            ></vdr-address-form>
+        </vdr-card>
+    </vdr-page-detail-sidebar>
+
+    <vdr-page-block>
+        <vdr-card [paddingX]="false">
+            <vdr-data-table-2 id="modify-order" class="order-table" [items]="order.lines.concat(addedLines)">
+                <!-- Here we define all the available columns -->
+                <vdr-dt2-column id="id" [heading]="'common.id' | translate" [hiddenByDefault]="true">
+                    <ng-template let-line="item">
+                        {{ line.id }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    id="created-at"
+                    [heading]="'common.created-at' | translate"
+                    [hiddenByDefault]="true"
+                >
+                    <ng-template let-line="item">
+                        {{ line.createdAt | localeDate : 'short' }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    id="updated-at"
+                    [heading]="'common.updated-at' | translate"
+                    [hiddenByDefault]="true"
+                >
+                    <ng-template let-line="item">
+                        {{ line.updatedAt | localeDate : 'short' }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column [heading]="'common.image' | translate" id="image">
+                    <ng-template let-line="item">
+                        <div class="image-placeholder">
+                            <img
+                                *ngIf="line.featuredAsset as asset; else imagePlaceholder"
+                                [src]="asset | assetPreview : 'tiny'"
+                            />
+                            <ng-template #imagePlaceholder>
+                                <div class="placeholder">
+                                    <clr-icon shape="image" size="48"></clr-icon>
+                                </div>
+                            </ng-template>
+                        </div>
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    id="product-name"
+                    [heading]="'order.product-name' | translate"
+                    [optional]="false"
+                >
+                    <ng-template let-line="item">
+                        {{ line.productVariant.name }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column id="product-sku" [heading]="'order.product-sku' | translate">
+                    <ng-template let-line="item">
+                        {{ line.productVariant.sku }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column id="unit-price" [heading]="'order.unit-price' | translate">
+                    <ng-template let-line="item">
+                        <div class="text-center">
+                            <div>{{ line.unitPriceWithTax | localeCurrency : order.currencyCode }}</div>
+                            <div class="net-price" [title]="'order.net-price' | translate">
+                                {{ line.unitPrice | localeCurrency : order.currencyCode }}
+                            </div>
+                        </div>
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column id="quantity" [heading]="'order.quantity' | translate" [optional]="false">
+                    <ng-template let-line="item">
+                        <input
+                            type="number"
+                            class="draft-qty mr-1"
+                            min="0"
+                            [value]="line.quantity"
+                            (input)="updateLineQuantity(line, $event.target.value)"
+                        />
                         <button
-                            class="btn btn-primary"
-                            [disabled]="!canPreviewChanges()"
-                            (click)="previewAndModify(order)"
+                            class="button-small"
+                            *ngIf="isAddedLine(line)"
+                            (click)="removeAddedItem(line.id)"
                         >
-                            {{ 'order.preview-changes' | translate }}
+                            <clr-icon shape="trash"></clr-icon>
                         </button>
+                        <vdr-line-refunds [line]="line" [payments]="order.payments"></vdr-line-refunds>
+                        <vdr-line-fulfillment
+                            [line]="line"
+                            [allOrderFulfillments]="order.fulfillments"
+                            [orderState]="order.state"
+                        ></vdr-line-fulfillment>
+                    </ng-template>
+                </vdr-dt2-column>
+            </vdr-data-table-2>
+        </vdr-card>
+        <vdr-card [title]="'order.add-item-to-order' | translate">
+            <vdr-product-variant-selector class="mb-4" (productSelected)="addItemSelectedVariant = $event">
+            </vdr-product-variant-selector>
+            <div class="flex">
+                <div>
+                    <div *ngIf="addItemSelectedVariant" class="flex mb-4">
+                        <img
+                            *ngIf="addItemSelectedVariant.productAsset as asset"
+                            [src]="asset | assetPreview : 'tiny'"
+                            class="mr-4 add-item-thumb"
+                        />
+                        <div>
+                            <strong class="mr-4">{{ addItemSelectedVariant.productVariantName }}</strong>
+                            <small>{{ addItemSelectedVariant.sku }}</small>
+                            <div>
+                                {{
+                                    getSelectedItemPrice(addItemSelectedVariant)
+                                        | localeCurrency : order.currencyCode
+                                }}
+                            </div>
+                        </div>
                     </div>
+                    <ng-container *ngFor="let customField of orderLineCustomFields">
+                        <vdr-custom-field-control
+                            [readonly]="!addItemSelectedVariant"
+                            [customField]="customField"
+                            [customFieldsFormGroup]="addItemCustomFieldsForm"
+                            entityName="OrderLine"
+                            [compact]="true"
+                        ></vdr-custom-field-control>
+                    </ng-container>
+                </div>
+                <div class="flex-spacer"></div>
+                <div>
+                    <button
+                        *ngIf="addItemSelectedVariant"
+                        class="btn btn-secondary"
+                        [disabled]="!addItemSelectedVariant || addItemCustomFieldsForm.invalid"
+                        (click)="addItemToOrder(addItemSelectedVariant)"
+                    >
+                        {{ 'order.add-item-to-order' | translate }}
+                    </button>
                 </div>
             </div>
-        </div>
-    </div>
-    <vdr-page-block> </vdr-page-block
-></vdr-page-block>
+        </vdr-card>
+        <vdr-card [title]="'order.add-surcharge' | translate">
+            <form [formGroup]="surchargeForm" (submit)="addSurcharge(surchargeForm.value)">
+                <div class="form-grid">
+                    <vdr-form-field [label]="'common.description' | translate" for="description"
+                        ><input id="description" type="text" formControlName="description"
+                    /></vdr-form-field>
+                    <vdr-form-field [label]="'order.product-sku' | translate" for="sku"
+                        ><input id="sku" type="text" formControlName="sku"
+                    /></vdr-form-field>
+                    <vdr-form-field [label]="'common.price' | translate" for="price">
+                        <vdr-currency-input
+                            [currencyCode]="order.currencyCode"
+                            id="price"
+                            formControlName="price"
+                        ></vdr-currency-input>
+                    </vdr-form-field>
+                    <vdr-form-field
+                        [label]="
+                            'catalog.price-includes-tax-at'
+                                | translate : { rate: surchargeForm.get('taxRate')?.value }
+                        "
+                        for="priceIncludesTax"
+                        ><input
+                            id="priceIncludesTax"
+                            type="checkbox"
+                            clrCheckbox
+                            formControlName="priceIncludesTax"
+                    /></vdr-form-field>
+                    <vdr-form-field [label]="'order.tax-rate' | translate" for="taxRate">
+                        <vdr-affixed-input suffix="%"
+                            ><input id="taxRate" type="number" min="0" max="100" formControlName="taxRate"
+                        /></vdr-affixed-input>
+                    </vdr-form-field>
+                    <vdr-form-field [label]="'order.tax-description' | translate" for="taxDescription"
+                        ><input id="taxDescription" type="text" formControlName="taxDescription"
+                    /></vdr-form-field>
+                </div>
+                <button
+                    class="btn btn-secondary mt-2"
+                    [disabled]="
+                        surchargeForm.invalid ||
+                        surchargeForm.pristine ||
+                        surchargeForm.get('price')?.value === 0 ||
+                        !surchargeForm.get('description')?.value
+                    "
+                >
+                    {{ 'order.add-surcharge' | translate }}
+                </button>
+            </form>
+        </vdr-card>
+    </vdr-page-block>
+</vdr-page-detail-layout>

+ 10 - 0
packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.scss

@@ -14,3 +14,13 @@
 .add-item-thumb {
     max-width: 50px;
 }
+
+.no-modifications {
+    color: var(--color-grey-400);
+}
+
+.summary-controls {
+    border-top: 1px solid var(--color-weight-200);
+    margin-top: calc(var(--space-unit) * 2);
+    padding-top: calc(var(--space-unit) * 1);
+}

+ 154 - 82
packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.ts

@@ -1,5 +1,12 @@
 import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
-import { UntypedFormArray, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
+import {
+    FormControl,
+    FormGroup,
+    UntypedFormArray,
+    UntypedFormControl,
+    UntypedFormGroup,
+    Validators,
+} from '@angular/forms';
 import {
     AddItemInput,
     CustomFieldConfig,
@@ -35,12 +42,15 @@ import {
 type ProductSelectorItem = ProductSelectorSearchQuery['search']['items'][number];
 
 interface AddedLine {
-    productVariantId: string;
-    productAsset?: ProductSelectorItem['productAsset'] | null;
-    productVariantName: string;
-    sku: string;
-    priceWithTax: number;
-    price: number;
+    id: string;
+    featuredAsset?: ProductSelectorItem['productAsset'] | null;
+    productVariant: {
+        id: string;
+        name: string;
+        sku: string;
+    };
+    unitPrice: number;
+    unitPriceWithTax: number;
     quantity: number;
 }
 
@@ -62,7 +72,7 @@ export class OrderEditorComponent
     availableCountries$: Observable<GetAvailableCountriesQuery['countries']['items']>;
     addressCustomFields: CustomFieldConfig[];
     detailForm = new UntypedFormGroup({});
-    couponCodesControl = new UntypedFormControl();
+    couponCodesControl = new FormControl<string[]>([]);
     orderLineCustomFieldsFormArray: UntypedFormArray;
     addItemCustomFieldsFormArray: UntypedFormArray;
     addItemCustomFieldsForm: UntypedFormGroup;
@@ -78,12 +88,41 @@ export class OrderEditorComponent
         updateShippingAddress: {},
         updateBillingAddress: {},
     };
-    surchargeForm: UntypedFormGroup;
-    shippingAddressForm: UntypedFormGroup;
-    billingAddressForm: UntypedFormGroup;
+    surchargeForm = new FormGroup({
+        description: new FormControl('', Validators.minLength(1)),
+        sku: new FormControl(''),
+        price: new FormControl(0),
+        priceIncludesTax: new FormControl(true),
+        taxRate: new FormControl(0),
+        taxDescription: new FormControl(''),
+    });
+    shippingAddressForm = new FormGroup({
+        fullName: new FormControl(''),
+        company: new FormControl(''),
+        streetLine1: new FormControl(''),
+        streetLine2: new FormControl(''),
+        city: new FormControl(''),
+        province: new FormControl(''),
+        postalCode: new FormControl(''),
+        countryCode: new FormControl(''),
+        phoneNumber: new FormControl(''),
+    });
+    billingAddressForm = new FormGroup({
+        fullName: new FormControl(''),
+        company: new FormControl(''),
+        streetLine1: new FormControl(''),
+        streetLine2: new FormControl(''),
+        city: new FormControl(''),
+        province: new FormControl(''),
+        postalCode: new FormControl(''),
+        countryCode: new FormControl(''),
+        phoneNumber: new FormControl(''),
+    });
     note = '';
     recalculateShipping = true;
     previousState: string;
+    editingShippingAddress = false;
+    editingBillingAddress = false;
     private addedVariants = new Map<string, ProductSelectorItem>();
 
     constructor(
@@ -95,24 +134,6 @@ export class OrderEditorComponent
         super();
     }
 
-    get addedLines(): AddedLine[] {
-        const getSinglePriceValue = (price: ProductSelectorItem['price']) =>
-            price.__typename === 'SinglePrice' ? price.value : 0;
-        return (this.modifyOrderInput.addItems || [])
-            .map(row => {
-                const variantInfo = this.addedVariants.get(row.productVariantId);
-                if (variantInfo) {
-                    return {
-                        ...variantInfo,
-                        price: getSinglePriceValue(variantInfo.price),
-                        priceWithTax: getSinglePriceValue(variantInfo.priceWithTax),
-                        quantity: row.quantity,
-                    };
-                }
-            })
-            .filter(notNullOrUndefined);
-    }
-
     ngOnInit(): void {
         this.init();
         this.addressCustomFields = this.getCustomFieldConfig('Address');
@@ -122,42 +143,15 @@ export class OrderEditorComponent
             if (order.couponCodes.length) {
                 this.couponCodesControl.setValue(order.couponCodes);
             }
-            this.surchargeForm = new UntypedFormGroup({
-                description: new UntypedFormControl('', Validators.required),
-                sku: new UntypedFormControl(''),
-                price: new UntypedFormControl(0, Validators.required),
-                priceIncludesTax: new UntypedFormControl(true),
-                taxRate: new UntypedFormControl(0),
-                taxDescription: new UntypedFormControl(''),
-            });
-            if (!this.shippingAddressForm) {
-                this.shippingAddressForm = new UntypedFormGroup({
-                    fullName: new UntypedFormControl(order.shippingAddress?.fullName),
-                    company: new UntypedFormControl(order.shippingAddress?.company),
-                    streetLine1: new UntypedFormControl(order.shippingAddress?.streetLine1),
-                    streetLine2: new UntypedFormControl(order.shippingAddress?.streetLine2),
-                    city: new UntypedFormControl(order.shippingAddress?.city),
-                    province: new UntypedFormControl(order.shippingAddress?.province),
-                    postalCode: new UntypedFormControl(order.shippingAddress?.postalCode),
-                    countryCode: new UntypedFormControl(order.shippingAddress?.countryCode),
-                    phoneNumber: new UntypedFormControl(order.shippingAddress?.phoneNumber),
-                });
-                this.addAddressCustomFieldsFormGroup(this.shippingAddressForm, order.shippingAddress);
+            this.surchargeForm.reset();
+            for (const [name, control] of Object.entries(this.shippingAddressForm.controls)) {
+                control.setValue(order.shippingAddress?.[name]);
             }
-            if (!this.billingAddressForm) {
-                this.billingAddressForm = new UntypedFormGroup({
-                    fullName: new UntypedFormControl(order.billingAddress?.fullName),
-                    company: new UntypedFormControl(order.billingAddress?.company),
-                    streetLine1: new UntypedFormControl(order.billingAddress?.streetLine1),
-                    streetLine2: new UntypedFormControl(order.billingAddress?.streetLine2),
-                    city: new UntypedFormControl(order.billingAddress?.city),
-                    province: new UntypedFormControl(order.billingAddress?.province),
-                    postalCode: new UntypedFormControl(order.billingAddress?.postalCode),
-                    countryCode: new UntypedFormControl(order.billingAddress?.countryCode),
-                    phoneNumber: new UntypedFormControl(order.billingAddress?.phoneNumber),
-                });
-                this.addAddressCustomFieldsFormGroup(this.billingAddressForm, order.billingAddress);
+            this.addAddressCustomFieldsFormGroup(this.shippingAddressForm, order.shippingAddress);
+            for (const [name, control] of Object.entries(this.billingAddressForm.controls)) {
+                control.setValue(order.billingAddress?.[name]);
             }
+            this.addAddressCustomFieldsFormGroup(this.billingAddressForm, order.billingAddress);
             this.orderLineCustomFieldsFormArray = new UntypedFormArray([]);
             for (const line of order.lines) {
                 const formGroup = new UntypedFormGroup({});
@@ -209,6 +203,71 @@ export class OrderEditorComponent
         this.destroy();
     }
 
+    get addedLines(): AddedLine[] {
+        const getSinglePriceValue = (price: ProductSelectorItem['price']) =>
+            price.__typename === 'SinglePrice' ? price.value : 0;
+        return (this.modifyOrderInput.addItems || [])
+            .map(row => {
+                const variantInfo = this.addedVariants.get(row.productVariantId);
+                if (variantInfo) {
+                    return {
+                        id: this.getIdForAddedItem(row),
+                        featuredAsset: variantInfo.productAsset,
+                        productVariant: {
+                            id: variantInfo.productVariantId,
+                            name: variantInfo.productVariantName,
+                            sku: variantInfo.sku,
+                        },
+                        unitPrice: getSinglePriceValue(variantInfo.price),
+                        unitPriceWithTax: getSinglePriceValue(variantInfo.priceWithTax),
+                        quantity: row.quantity,
+                    };
+                }
+            })
+            .filter(notNullOrUndefined);
+    }
+
+    get adjustedLines(): string[] {
+        return (this.modifyOrderInput.adjustOrderLines || [])
+            .map(l => {
+                const line = this.entity?.lines.find(line => line.id === l.orderLineId);
+                if (line) {
+                    const delta = l.quantity - line.quantity;
+                    const sign = delta === 0 ? '' : delta > 0 ? '+' : '-';
+                    return delta
+                        ? `${sign}${Math.abs(delta)} ${line.productVariant.name}`
+                        : line.productVariant.name;
+                }
+            })
+            .filter(notNullOrUndefined);
+    }
+
+    get couponCodeChanges(): string[] {
+        const originalCodes = this.entity?.couponCodes || [];
+        const newCodes = this.couponCodesControl.value || [];
+        const addedCodes = newCodes.filter(c => !originalCodes.includes(c)).map(c => `+ ${c}`);
+        const removedCodes = originalCodes.filter(c => !newCodes.includes(c)).map(c => `- ${c}`);
+        return [...addedCodes, ...removedCodes];
+    }
+
+    getModifiedFields(formGroup: FormGroup): string {
+        if (!formGroup.dirty) {
+            return '';
+        }
+        return Object.entries(formGroup.controls)
+            .map(([key, control]) => {
+                if (control.dirty) {
+                    return key;
+                }
+            })
+            .filter(notNullOrUndefined)
+            .join(', ');
+    }
+
+    private getIdForAddedItem(row: ModifyOrderData['addItems'][number]) {
+        return `added-${row.productVariantId}-${JSON.stringify(row.customFields || {})}`;
+    }
+
     transitionToPriorState(order: OrderDetailFragment) {
         this.orderTransitionService
             .transitionToPreModifyingState(order.id, order.nextStates)
@@ -217,7 +276,7 @@ export class OrderEditorComponent
             });
     }
 
-    canPreviewChanges(): boolean {
+    hasModifications(): boolean {
         const { addItems, adjustOrderLines, surcharges } = this.modifyOrderInput;
         return (
             !!addItems?.length ||
@@ -235,30 +294,43 @@ export class OrderEditorComponent
         );
     }
 
-    updateLineQuantity(line: OrderDetailFragment['lines'][number], quantity: string) {
+    updateLineQuantity(line: OrderDetailFragment['lines'][number] | AddedLine, quantity: string) {
         const { adjustOrderLines } = this.modifyOrderInput;
-        let row = adjustOrderLines?.find(l => l.orderLineId === line.id);
-        if (row && +quantity === line.quantity) {
-            // Remove the modification if the quantity is the same as
-            // the original order
-            adjustOrderLines?.splice(adjustOrderLines?.indexOf(row), 1);
-        }
-        if (!row) {
-            row = { orderLineId: line.id, quantity: +quantity };
-            adjustOrderLines?.push(row);
+        if (this.isAddedLine(line)) {
+            const row = this.modifyOrderInput.addItems?.find(
+                l => l.productVariantId === line.productVariant.id,
+            );
+            if (row) {
+                row.quantity = +quantity;
+            }
+        } else {
+            let row = adjustOrderLines?.find(l => l.orderLineId === line.id);
+            if (row && +quantity === line.quantity) {
+                // Remove the modification if the quantity is the same as
+                // the original order
+                adjustOrderLines?.splice(adjustOrderLines?.indexOf(row), 1);
+            }
+            if (!row) {
+                row = { orderLineId: line.id, quantity: +quantity };
+                adjustOrderLines?.push(row);
+            }
+            row.quantity = +quantity;
         }
-        row.quantity = +quantity;
+    }
+
+    isAddedLine(line: OrderDetailFragment['lines'][number] | AddedLine): line is AddedLine {
+        return (line as AddedLine).id.startsWith('added-');
     }
 
     updateAddedItemQuantity(item: AddedLine, quantity: string) {
-        const row = this.modifyOrderInput.addItems?.find(l => l.productVariantId === item.productVariantId);
+        const row = this.modifyOrderInput.addItems?.find(l => l.productVariantId === item.productVariant.id);
         if (row) {
             row.quantity = +quantity;
         }
     }
 
     trackByProductVariantId(index: number, item: AddedLine) {
-        return item.productVariantId;
+        return item.productVariant.id;
     }
 
     getSelectedItemPrice(result: ProductSelectorItem | undefined): number {
@@ -317,11 +389,11 @@ export class OrderEditorComponent
         );
     }
 
-    removeAddedItem(index: number) {
-        this.modifyOrderInput.addItems.splice(index, 1);
-        if (-1 < index) {
-            this.addItemCustomFieldsFormArray.removeAt(index);
-        }
+    removeAddedItem(id: string) {
+        this.modifyOrderInput.addItems = this.modifyOrderInput.addItems?.filter(l => {
+            const itemId = this.getIdForAddedItem(l);
+            return itemId !== id;
+        });
     }
 
     getSurchargePrices(surcharge: SurchargeInput) {

+ 1 - 1
packages/admin-ui/src/lib/order/src/order.module.ts

@@ -180,7 +180,7 @@ export class OrderModule {
                         link: ['/orders/', entity?.id],
                     },
                     {
-                        label: _('order.modify-order'),
+                        label: _('breadcrumb.modifying-order'),
                         link: [entity?.id],
                     },
                 ],

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/ar.json

@@ -37,7 +37,7 @@
     "global-settings": "الاعدادات العامة",
     "job-queue": "ذيل الوظيفة",
     "manage-variants": "إدارة المتغيرات",
-    "modifying": "تعديل",
+    "modifying-order": "تعديل الطلب",
     "orders": "طلبيات",
     "payment-methods": "طرق الدفع",
     "product-options": "خيارات المنتج",
@@ -601,11 +601,11 @@
     "modification-summary": "ملخص التعديلات",
     "modification-updating-billing-address": "تحديث عنوان الفواتير",
     "modification-updating-shipping-address": "تحديث عنوان الشحن",
-    "modifications": "التعديلات",
     "modify-order": "تعديل الترتيب",
     "modify-order-price-difference": "فرق السعر",
     "net-price": "السعر الصافي",
     "new-customer": "عميل جديد",
+    "no-modifications-made": "لم يتم إجراء أي تعديلات",
     "note": "ملحوظة",
     "note-is-private": "ملاحظة خاصة",
     "note-only-visible-to-administrators": "مرئي للمسؤولين فقط",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/cs.json

@@ -37,7 +37,7 @@
     "global-settings": "Všeobecné nastavení",
     "job-queue": "Fronta úloh",
     "manage-variants": "Správa variant",
-    "modifying": "Úpravy",
+    "modifying-order": "Modifikace objednávky",
     "orders": "Objednávky",
     "payment-methods": "Platební metody",
     "product-options": "",
@@ -601,11 +601,11 @@
     "modification-summary": "Souhrn úprav",
     "modification-updating-billing-address": "Upravování fakturační adresy",
     "modification-updating-shipping-address": "Upravování dodací adresy",
-    "modifications": "Úpravy",
     "modify-order": "Upravit objednávku",
     "modify-order-price-difference": "Cenový rozdíl",
     "net-price": "Čistá cena",
     "new-customer": "Nový zákazník",
+    "no-modifications-made": "Nebyly provedeny žádné úpravy",
     "note": "Poznámka",
     "note-is-private": "Interní poznámka",
     "note-only-visible-to-administrators": "Pouze pro adminy",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/de.json

@@ -37,7 +37,7 @@
     "global-settings": "Globale Einstellungen",
     "job-queue": "Job-Warteschlange",
     "manage-variants": "Varianten verwalten",
-    "modifying": "Bearbeiten",
+    "modifying-order": "Bestellung bearbeiten",
     "orders": "Bestellungen",
     "payment-methods": "Zahlungsarten",
     "product-options": "Produktoptionen",
@@ -601,11 +601,11 @@
     "modification-summary": "Zusammenfassung der Änderungen",
     "modification-updating-billing-address": "Rechnungsadresse aktualisieren",
     "modification-updating-shipping-address": "Versandadresse aktualisieren",
-    "modifications": "Änderungen",
     "modify-order": "Bestellung ändern",
     "modify-order-price-difference": "Preisunterschied",
     "net-price": "Nettopreis",
     "new-customer": "Neuer Kunde",
+    "no-modifications-made": "Es wurden keine Änderungen vorgenommen",
     "note": "Notiz",
     "note-is-private": "Notiz ist privat",
     "note-only-visible-to-administrators": "Nur für Administratoren sichtbar",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/en.json

@@ -37,7 +37,7 @@
     "global-settings": "Global settings",
     "job-queue": "Job queue",
     "manage-variants": "Manage variants",
-    "modifying": "Modifying",
+    "modifying-order": "Modifying order",
     "orders": "Orders",
     "payment-methods": "Payment methods",
     "product-options": "Product options",
@@ -601,11 +601,11 @@
     "modification-summary": "Summary of modifications",
     "modification-updating-billing-address": "Updating billing address",
     "modification-updating-shipping-address": "Updating shipping address",
-    "modifications": "Modifications",
     "modify-order": "Modify order",
     "modify-order-price-difference": "Price difference",
     "net-price": "Net price",
     "new-customer": "New customer",
+    "no-modifications-made": "No modifications have been made",
     "note": "Note",
     "note-is-private": "Note is private",
     "note-only-visible-to-administrators": "Visible to admins only",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/es.json

@@ -37,7 +37,7 @@
     "global-settings": "Ajustes globales",
     "job-queue": "Cola de tareas",
     "manage-variants": "Gestionar variantes",
-    "modifying": "Modificando",
+    "modifying-order": "Modificando orden",
     "orders": "Pedidos",
     "payment-methods": "Métodos de pago",
     "product-options": "Opciones de producto",
@@ -601,11 +601,11 @@
     "modification-summary": "Resumen de modificaciones",
     "modification-updating-billing-address": "Actualizando dirección de facturación",
     "modification-updating-shipping-address": "Actualizando dirección de envío",
-    "modifications": "Modificaciones",
     "modify-order": "Modificar pedido",
     "modify-order-price-difference": "Diferencia de precio",
     "net-price": "Precio neto",
     "new-customer": "Nuevo cliente",
+    "no-modifications-made": "No se han realizado modificaciones",
     "note": "Nota",
     "note-is-private": "La nota es privada",
     "note-only-visible-to-administrators": "Visible sólo para administradores",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/fa.json

@@ -37,7 +37,7 @@
     "global-settings": "تنظیمات جهانی",
     "job-queue": "صف کارها",
     "manage-variants": "مدیریت انواع",
-    "modifying": "درحال تغییر",
+    "modifying-order": "تغییر سفارش",
     "orders": "سفارشات",
     "payment-methods": "روش های پرداخت",
     "product-options": "گزینه های محصول",
@@ -601,11 +601,11 @@
     "modification-summary": "خلاصه تغییرات",
     "modification-updating-billing-address": "بروزرسانی آدرس صورتحساب",
     "modification-updating-shipping-address": "بروزرسانی آدرس حمل و نقل",
-    "modifications": "تغییرات",
     "modify-order": "تغییر سفارش",
     "modify-order-price-difference": "تفاوت قیمتی",
     "net-price": "قیمت کل",
     "new-customer": "مشتری جدید",
+    "no-modifications-made": "هیچ تغییری انجام نشده است",
     "note": "یادداشت",
     "note-is-private": "یادداشت شخصی است",
     "note-only-visible-to-administrators": "فقط برای مدیران قابل مشاهده است",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/fr.json

@@ -37,7 +37,7 @@
     "global-settings": "Paramètres globaux",
     "job-queue": "File d'attente de tâches",
     "manage-variants": "Gestion des variations",
-    "modifying": "Modification",
+    "modifying-order": "Modification de la commande",
     "orders": "Commandes",
     "payment-methods": "Modes de paiement",
     "product-options": "Options de produit",
@@ -601,11 +601,11 @@
     "modification-summary": "Résumé des modifications",
     "modification-updating-billing-address": "Mise à jour de l'adresse de facturation",
     "modification-updating-shipping-address": "Mise à jour de l'adresse de livraison",
-    "modifications": "Modifications",
     "modify-order": "Modifier la commande",
     "modify-order-price-difference": "Différence de prix",
     "net-price": "Prix net",
     "new-customer": "Nouveau client",
+    "no-modifications-made": "Aucune modification n'a été apportée",
     "note": "Note",
     "note-is-private": "La note est privée",
     "note-only-visible-to-administrators": "Visible par les admins uniquement",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/he.json

@@ -37,7 +37,7 @@
     "global-settings": "הגדרות גלובליות",
     "job-queue": "תור משימות",
     "manage-variants": "נהל וריאנטים",
-    "modifying": "משנה",
+    "modifying-order": "שינוי הזמנה",
     "orders": "הזמנות",
     "payment-methods": "שיטות תשלום",
     "product-options": "אפשרויות מוצר",
@@ -601,11 +601,11 @@
     "modification-summary": "סיכום השינויים",
     "modification-updating-billing-address": "מעדכן כתובת לחיוב",
     "modification-updating-shipping-address": "מעדכן כתובת למשלוח",
-    "modifications": "שינויים",
     "modify-order": "שנה הזמנה",
     "modify-order-price-difference": "הפרש מחיר",
     "net-price": "מחיר נטו",
     "new-customer": "לקוח חדש",
+    "no-modifications-made": "לא בוצעו שינויים",
     "note": "הערה",
     "note-is-private": "הערה פרטית",
     "note-only-visible-to-administrators": "נראה רק למנהלים",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/hr.json

@@ -37,7 +37,7 @@
     "global-settings": "Globalne postavke",
     "job-queue": "Red poslova",
     "manage-variants": "Upravljaj varijantama",
-    "modifying": "Uređivanje",
+    "modifying-order": "Izmjena narudžbe",
     "orders": "Narudžbe",
     "payment-methods": "Načini plaćanja",
     "product-options": "Opcije proizvoda",
@@ -601,11 +601,11 @@
     "modification-summary": "Sažetak izmjena",
     "modification-updating-billing-address": "Ažuriranje adrese za naplatu",
     "modification-updating-shipping-address": "Ažuriranje adrese za dostavu",
-    "modifications": "Izmjene",
     "modify-order": "Izmijeni narudžbu",
     "modify-order-price-difference": "Razlika u cijeni",
     "net-price": "Neto cijena",
     "new-customer": "Novi kupac",
+    "no-modifications-made": "Nisu napravljene nikakve izmjene",
     "note": "Napomena",
     "note-is-private": "Napomena je privatna",
     "note-only-visible-to-administrators": "Vidljivo samo administratorima",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/it.json

@@ -37,7 +37,7 @@
     "global-settings": "Impostazioni Globali",
     "job-queue": "Coda operazioni",
     "manage-variants": "Gestione varianti",
-    "modifying": "Modifica",
+    "modifying-order": "Modifica ordine",
     "orders": "Ordini",
     "payment-methods": "Metodi di pagamento",
     "product-options": "Opzioni prodotto",
@@ -601,11 +601,11 @@
     "modification-summary": "Riepilogo delle modifiche",
     "modification-updating-billing-address": "Aggiornando l'indirizzo di fatturazione",
     "modification-updating-shipping-address": "Aggiornando l'indirizzo di spedizione",
-    "modifications": "Modifiche",
     "modify-order": "Modifica ordine",
     "modify-order-price-difference": "Differenza di prezzo",
     "net-price": "Prezzo netto",
     "new-customer": "Nuovo cliente",
+    "no-modifications-made": "Non sono state apportate modifiche",
     "note": "Nota",
     "note-is-private": "Le note sono private",
     "note-only-visible-to-administrators": "Visibile solo agli amministratori",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/nb.json

@@ -37,7 +37,7 @@
     "global-settings": "Global innstillinger",
     "job-queue": "Jobbkø",
     "manage-variants": "Administrer varianter",
-    "modifying": "Modifisering",
+    "modifying-order": "Endrer ordre",
     "orders": "Ordre",
     "payment-methods": "Betalingsmetoder",
     "product-options": "Produktalternativer",
@@ -601,11 +601,11 @@
     "modification-summary": "Sammendrag av endringer",
     "modification-updating-billing-address": "Oppdaterer faktureringsadresse",
     "modification-updating-shipping-address": "Oppdaterer leveringsadresse",
-    "modifications": "Endringer",
     "modify-order": "Endre ordre",
     "modify-order-price-difference": "Prisforskjell",
     "net-price": "Nettopris",
     "new-customer": "Ny kunde",
+    "no-modifications-made": "Ingen endringer er gjort",
     "note": "Merknad",
     "note-is-private": "Merknad er privat",
     "note-only-visible-to-administrators": "Synlig kun for administratorer",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/ne.json

@@ -37,7 +37,7 @@
     "global-settings": "वैश्विक सेटिङहरू",
     "job-queue": "काम कत्ति",
     "manage-variants": "विविध विकल्पहरू प्रबन्ध गर्नुहोस्",
-    "modifying": "परिमार्जन",
+    "modifying-order": "आदान-प्रदान परिवर्तन",
     "orders": "ओर्दरहरु",
     "payment-methods": "भुक्तानी विधिहरू",
     "product-options": "समान विकल्पहरू",
@@ -601,11 +601,11 @@
     "modification-summary": "संशोधनको संक्षेप",
     "modification-updating-billing-address": "बिलिङ ठेगाना अपडेट गरिएको छ",
     "modification-updating-shipping-address": "पारिश्रमिक ठेगाना अपडेट गरिएको छ",
-    "modifications": "संशोधनहरू",
     "modify-order": "ओर्दर संशोधन गर्नुहोस्",
     "modify-order-price-difference": "मूल्य अन्तर",
     "net-price": "नेट मूल्य",
     "new-customer": "नयाँ ग्राहक",
+    "no-modifications-made": "कुनै परिवर्तन गरिएको छैन",
     "note": "टिप्पणी",
     "note-is-private": "टिप्पणी प्राइभेट छ",
     "note-only-visible-to-administrators": "मात्र प्रशासकहरूले मात्र हेर्न सक्छन्",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/pl.json

@@ -37,7 +37,7 @@
     "global-settings": "Ustawienia globalne",
     "job-queue": "Kolejka zadań",
     "manage-variants": "Zarządzaj wariantami",
-    "modifying": "",
+    "modifying-order": "Modyfikowanie zamówienia",
     "orders": "Zamówienia",
     "payment-methods": "Metody płatności",
     "product-options": "",
@@ -601,11 +601,11 @@
     "modification-summary": "",
     "modification-updating-billing-address": "",
     "modification-updating-shipping-address": "",
-    "modifications": "",
     "modify-order": "",
     "modify-order-price-difference": "",
     "net-price": "Cena netto",
     "new-customer": "Nowy klient",
+    "no-modifications-made": "Nie dokonano żadnych modyfikacji",
     "note": "",
     "note-is-private": "Notatka jest prywatna",
     "note-only-visible-to-administrators": "Widoczne tylko dla administratora",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -37,7 +37,7 @@
     "global-settings": "Configurações globais",
     "job-queue": "Fila de tabalho",
     "manage-variants": "Gerenciamento de variações",
-    "modifying": "Modificando",
+    "modifying-order": "Modificando pedido",
     "orders": "Pedidos",
     "payment-methods": "Métodos de pagamentos",
     "product-options": "Opções do produto",
@@ -601,11 +601,11 @@
     "modification-summary": "Resumo de modificações",
     "modification-updating-billing-address": "Atualizando endereço de fatura",
     "modification-updating-shipping-address": "Atualizando endereço de envio",
-    "modifications": "Modificações",
     "modify-order": "Modificar pedido",
     "modify-order-price-difference": "Preço diference",
     "net-price": "Preço líquido",
     "new-customer": "Novo cliente",
+    "no-modifications-made": "Nenhuma modificação foi feita",
     "note": "Nota",
     "note-is-private": "Nota é privada",
     "note-only-visible-to-administrators": "Visível somente para administradores",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json

@@ -37,7 +37,7 @@
     "global-settings": "Configurações globais",
     "job-queue": "Fila de tabalho",
     "manage-variants": "Gerir variações",
-    "modifying": "A modificar",
+    "modifying-order": "Modificando pedido",
     "orders": "Encomendas",
     "payment-methods": "Métodos de pagamentos",
     "product-options": "Opções",
@@ -601,11 +601,11 @@
     "modification-summary": "Resumo de modificações",
     "modification-updating-billing-address": "A actualizar morada de faturação",
     "modification-updating-shipping-address": "A actualizar morada de entrega",
-    "modifications": "Modificações",
     "modify-order": "Modificar pedido",
     "modify-order-price-difference": "Diferença de preço",
     "net-price": "Preço líquido",
     "new-customer": "Novo cliente",
+    "no-modifications-made": "Nenhuma modificação foi feita",
     "note": "Nota",
     "note-is-private": "Marcar como privada",
     "note-only-visible-to-administrators": "Visível somente para administradores",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/ru.json

@@ -37,7 +37,7 @@
     "global-settings": "Глобальные настройки",
     "job-queue": "Очередь заданий",
     "manage-variants": "Управление вариантами",
-    "modifying": "Изменение",
+    "modifying-order": "Изменение заказа",
     "orders": "Заказы",
     "payment-methods": "Способы оплаты",
     "product-options": "Опции товара",
@@ -601,11 +601,11 @@
     "modification-summary": "Сводка модификаций",
     "modification-updating-billing-address": "Обновление платежного адреса",
     "modification-updating-shipping-address": "Обновление адреса доставки",
-    "modifications": "Модификации",
     "modify-order": "Изменить порядок",
     "modify-order-price-difference": "Разница в цене",
     "net-price": "Цена нетто",
     "new-customer": "Новый клиент",
+    "no-modifications-made": "Изменений не внесено",
     "note": "Примечание",
     "note-is-private": "Заметка является приватной",
     "note-only-visible-to-administrators": "Доступно только администраторам",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/uk.json

@@ -37,7 +37,7 @@
     "global-settings": "Глобальні налаштування",
     "job-queue": "Черга завдань",
     "manage-variants": "Управління варіантами",
-    "modifying": "Зміна",
+    "modifying-order": "Модифікація замовлення",
     "orders": "Замовлення",
     "payment-methods": "Способи оплати",
     "product-options": "",
@@ -601,11 +601,11 @@
     "modification-summary": "Зведення модифікацій",
     "modification-updating-billing-address": "Оновлення платіжної адреси",
     "modification-updating-shipping-address": "Оновлення адреси доставки",
-    "modifications": "Модифікації",
     "modify-order": "Змінити порядок",
     "modify-order-price-difference": "Різниця в ціні",
     "net-price": "Ціна нетто",
     "new-customer": "Новий клієнт",
+    "no-modifications-made": "Жодних модифікацій не зроблено",
     "note": "Примітка",
     "note-is-private": "Примітка є службовою",
     "note-only-visible-to-administrators": "Доступно тільки адміністраторам",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json

@@ -37,7 +37,7 @@
     "global-settings": "语言设置",
     "job-queue": "任务队列",
     "manage-variants": "商品规格管理",
-    "modifying": "正在修改",
+    "modifying-order": "修改订单",
     "orders": "订单管理",
     "payment-methods": "支付管理",
     "product-options": "",
@@ -601,11 +601,11 @@
     "modification-summary": "",
     "modification-updating-billing-address": "",
     "modification-updating-shipping-address": "",
-    "modifications": "",
     "modify-order": "",
     "modify-order-price-difference": "",
     "net-price": "净价",
     "new-customer": "新客户",
+    "no-modifications-made": "没有进行任何修改",
     "note": "",
     "note-is-private": "隐藏备注",
     "note-only-visible-to-administrators": "仅管理员可见",

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

@@ -37,7 +37,7 @@
     "global-settings": "語言",
     "job-queue": "",
     "manage-variants": "商品規格管理",
-    "modifying": "",
+    "modifying-order": "修改訂單",
     "orders": "訂單管理",
     "payment-methods": "支付方式",
     "product-options": "",
@@ -601,11 +601,11 @@
     "modification-summary": "",
     "modification-updating-billing-address": "",
     "modification-updating-shipping-address": "",
-    "modifications": "",
     "modify-order": "",
     "modify-order-price-difference": "",
     "net-price": "淨價",
     "new-customer": "新客戶",
+    "no-modifications-made": "沒有進行任何修改",
     "note": "",
     "note-is-private": "隱藏備注",
     "note-only-visible-to-administrators": "僅管理員可瀏覽",