Skip to content

Commit 275a33d

Browse files
CXIEP-7764: Display Sales order attachments
1 parent 03cebd9 commit 275a33d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1853
-4
lines changed

integration-libs/s4om/assets/translations/en/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
*/
66

77
import s4omScheduleLines from './s4omScheduleLines.json';
8+
import s4omOrder from './s4omOrder.json';
9+
810
export const en = {
911
s4omScheduleLines,
12+
s4omOrder
1013
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"s4omOrder": {
3+
"attachments": {
4+
"button": "View Order Attachments",
5+
"dialog": {
6+
"title": "Attachments",
7+
"preview": "Preview file",
8+
"closeModal": "Close Modal",
9+
"error": "An error has occurred. Refresh the page or try again later.",
10+
"empty": "Documents are unavailable. You can view the documents here once they are added.",
11+
"downloadError": "An error occured while fetching documents. Refresh the page or try again later."
12+
}
13+
}
14+
}
15+
}

integration-libs/s4om/assets/translations/translations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { TranslationChunksConfig } from '@spartacus/core';
88

99
export const s4omTranslationChunksConfig: TranslationChunksConfig = {
1010
s4omScheduleLines: ['s4omScheduleLines'],
11+
s4omOrder: ['s4omOrder'],
1112
};
1213

1314
export { cs as s4omTranslationsCs } from './cs/index';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 SAP Spartacus team <spartacus-team@sap.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import { AuthGuard, CmsConfig } from '@spartacus/core';
8+
import { OrderDetailAttachmentsComponent } from '../order-detail-attachments/order-detail-attachments.component';
9+
10+
export const defaultOrderCmsConfig: CmsConfig = {
11+
cmsComponents: {
12+
AccountOrderDetailsOrderAttachmentsComponent: {
13+
component: OrderDetailAttachmentsComponent,
14+
guards: [AuthGuard],
15+
},
16+
},
17+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 SAP Spartacus team <spartacus-team@sap.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import { DIALOG_TYPE, LayoutConfig } from '@spartacus/storefront';
8+
import { AttachmentsDialogComponent } from '../order-detail-attachments/attachments-dialog/attachments-dialog.component';
9+
10+
export const defaultOrderAttachmentsLayoutConfig: LayoutConfig = {
11+
launch: {
12+
S4OM_ORDER_ATTACHMENTS: {
13+
inline: true,
14+
component: AttachmentsDialogComponent,
15+
dialogType: DIALOG_TYPE.DIALOG,
16+
},
17+
},
18+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 SAP Spartacus team <spartacus-team@sap.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import { InjectionToken } from '@angular/core';
8+
9+
export interface S4OMOrderAttachmentsPreviewMimeTypesConfig {
10+
previewMimeTypes: string[];
11+
}
12+
13+
export const DEFAULT_MIME_TYPE_CONFIG: S4OMOrderAttachmentsPreviewMimeTypesConfig = {
14+
previewMimeTypes: [
15+
'text/plain',
16+
'application/json',
17+
'application/xml',
18+
'application/xhtml+xml',
19+
'image/jpeg',
20+
'image/png',
21+
'image/gif',
22+
'image/bmp',
23+
'image/svg+xml',
24+
'image/webp',
25+
'image/x-icon',
26+
'image/tiff',
27+
'application/pdf',
28+
],
29+
};
30+
31+
export const S4OM_ORDER_ATTACHMENTS_PREVIEW_MIME_TYPES =
32+
new InjectionToken<S4OMOrderAttachmentsPreviewMimeTypesConfig>('S4OMOrderAttachmentsPreviewMimeTypesConfig');
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 SAP Spartacus team <spartacus-team@sap.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
export * from './s4om-components.module';
8+
export * from './order-detail-attachments/order-detail-attachments.component';
9+
export * from './order-detail-attachments/attachments-dialog/attachments-dialog.component';
10+
export * from './config/order-attachments-mime-types.config';
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<div
2+
[cxFocus]="focusConfig"
3+
(esc)="close('Escape clicked')"
4+
class="cx-modal-container"
5+
role="dialog"
6+
aria-labelledby="dialogTitle"
7+
aria-modal="true"
8+
>
9+
<div class="cx-modal-content">
10+
<ng-container>
11+
<div class="cx-dialog-header modal-header">
12+
<div id="dialogTitle" class="cx-dialog-title modal-title">
13+
<span>
14+
{{ 's4omOrder.attachments.dialog.title' | cxTranslate }}
15+
</span>
16+
@if (attachmentsCount$ | async; as attachmentsCount) {
17+
@if (attachmentsCount > 0) {
18+
<span class="attachments-counter">
19+
{{ '(' + attachmentsCount + ')' }}
20+
</span>
21+
}
22+
}
23+
</div>
24+
<button
25+
type="button"
26+
class="close"
27+
attr.aria-label="{{ 's4omOrder.attachments.dialog.closeModal' | cxTranslate }}"
28+
title="{{ 's4omOrder.attachments.dialog.closeModal' | cxTranslate }}"
29+
(click)="close('Close dialog')"
30+
>
31+
<span aria-hidden="true">
32+
<cx-icon [type]="iconTypes.CLOSE"></cx-icon>
33+
</span>
34+
</button>
35+
</div>
36+
</ng-container>
37+
38+
<!-- Modal Body -->
39+
<div class="cx-dialog-body modal-body">
40+
@for (errorId of erroredAttachments; track errorId) {
41+
<div class="cx-dialog-message attachment-error" aria-live="assertive" aria-atomic="true">
42+
<cx-message
43+
[text]="'s4omOrder.attachments.dialog.downloadError' | cxTranslate"
44+
[type]="globalMessageType.MSG_TYPE_ERROR"
45+
(closeMessage)="closeErrorMessage(errorId)"
46+
>
47+
</cx-message>
48+
</div>
49+
}
50+
@if (attachments$ | async; as attachments) {
51+
@if (!(error$ | async)) {
52+
<table class="table">
53+
@for (attachment of attachments; track attachment.attachmentId) {
54+
@if (attachment.attachmentId) {
55+
<tr class="order-attachment-row">
56+
<td>
57+
<a
58+
attr.aria-label="{{ 's4omOrder.attachments.dialog.preview' | cxTranslate }}"
59+
title="{{ 's4omOrder.attachments.dialog.preview' | cxTranslate }}"
60+
[ngClass]="{'disabled': loadingAttachments.includes(attachment.attachmentId)}"
61+
(mousedown)="onMouseDown($event, attachment.attachmentId, attachment.fileName)"
62+
(keydown.enter)="openOrderAttachment(attachment.attachmentId, attachment.fileName)"
63+
>
64+
{{ attachment.fileName }}
65+
</a>
66+
</td>
67+
<td>
68+
<div class="inline-spinner"
69+
[ngClass]="{hidden: !loadingAttachments.includes(attachment.attachmentId)}">
70+
<cx-spinner></cx-spinner>
71+
</div>
72+
</td>
73+
<td>
74+
<a
75+
tabindex="0"
76+
role="button"
77+
class="file-icon"
78+
attr.aria-label="{{ 's4omOrder.attachments.dialog.preview' | cxTranslate }}"
79+
title="{{ 's4omOrder.attachments.dialog.preview' | cxTranslate }}"
80+
[ngClass]="{'disabled': loadingAttachments.includes(attachment.attachmentId)}"
81+
(click)="openOrderAttachment(attachment.attachmentId, attachment.fileName)"
82+
(keydown.enter)="openOrderAttachment(attachment.attachmentId, attachment.fileName)"
83+
>
84+
<cx-icon [type]="iconTypes.FILE"></cx-icon>
85+
</a>
86+
</td>
87+
</tr>
88+
}
89+
} @empty {
90+
<div class="cx-dialog-message info-message" aria-live="assertive" aria-atomic="true">
91+
<cx-message
92+
[text]="'s4omOrder.attachments.dialog.empty' | cxTranslate"
93+
[type]="globalMessageType.MSG_TYPE_INFO"
94+
[isVisibleCloseButton]="false"
95+
>
96+
</cx-message>
97+
</div>
98+
}
99+
</table>
100+
} @else {
101+
<div class="cx-dialog-message error-message" aria-live="assertive" aria-atomic="true">
102+
<cx-message
103+
[text]="'s4omOrder.attachments.dialog.error' | cxTranslate"
104+
[type]="globalMessageType.MSG_TYPE_ERROR"
105+
[isVisibleCloseButton]="false"
106+
>
107+
</cx-message>
108+
</div>
109+
}
110+
} @else {
111+
<div class="cx-spinner">
112+
<cx-spinner></cx-spinner>
113+
</div>
114+
}
115+
</div>
116+
117+
<!-- Modal Footer -->
118+
<div class="cx-dialog-footer modal-footer">
119+
<button
120+
(click)="close('Cancel dialog')"
121+
[attr.aria-label]="'common.cancel' | cxTranslate"
122+
class="btn btn-secondary cancel-button"
123+
type="button"
124+
>
125+
{{ 'common.cancel' | cxTranslate }}
126+
</button>
127+
</div>
128+
</div>
129+
</div>

0 commit comments

Comments
 (0)