@haus-tech/badge-plugin 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,15 +35,8 @@ let BadgePlugin = BadgePlugin_1 = class BadgePlugin {
35
35
  en: path_1.default.join(__dirname, 'ui/translations/en.json'),
36
36
  sv: path_1.default.join(__dirname, 'ui/translations/sv.json'),
37
37
  },
38
- ngModules: [
39
- {
40
- type: 'lazy',
41
- route: 'badges',
42
- ngModuleFileName: 'badge.module.ts',
43
- ngModuleName: 'BadgeModule',
44
- },
45
- ],
46
38
  providers: ['providers.ts'],
39
+ routes: [{ route: 'badges', filePath: 'routes.ts' }],
47
40
  };
48
41
  };
49
42
  BadgePlugin = BadgePlugin_1 = __decorate([
@@ -0,0 +1,78 @@
1
+ <vdr-page-block style="width: 100%">
2
+ <div class="my-2" style="width: 100%">
3
+ <vdr-page-block>
4
+ <vdr-action-bar>
5
+ <vdr-ab-left></vdr-ab-left>
6
+ <vdr-ab-right>
7
+ <vdr-asset-file-input
8
+ (selectFiles)="filesSelected($event)"
9
+ [uploading]="uploading"
10
+ dropZoneTarget=".content-area"
11
+ ></vdr-asset-file-input>
12
+ </vdr-ab-right>
13
+ </vdr-action-bar>
14
+ </vdr-page-block>
15
+ </div>
16
+ <div class="gallery-wrapper">
17
+ <div class="gallery">
18
+ <div
19
+ class="card"
20
+ *ngFor="let item of items$ | async"
21
+ (click)="toggleSelection(item, $event)"
22
+ [class.selected]="isSelected(item)"
23
+ >
24
+ <div class="card-img">
25
+ <vdr-select-toggle
26
+ [selected]="isSelected(item)"
27
+ [disabled]="true"
28
+ [hiddenWhenOff]="true"
29
+ ></vdr-select-toggle>
30
+ <img class="asset-thumb" [src]="item.asset | assetPreview : 'thumb'" />
31
+ </div>
32
+ <div class="detail">
33
+ <span [title]="item.position">{{ item.position }}</span>
34
+ </div>
35
+ </div>
36
+ </div>
37
+
38
+ <div class="info-bar">
39
+ <div class="card">
40
+ <div class="card-img">
41
+ <div class="placeholder" *ngIf="selectionManager.selection.length === 0">
42
+ <clr-icon shape="image" size="128"></clr-icon>
43
+ <div>{{ 'catalog.no-selection' | translate }}</div>
44
+ </div>
45
+ <img
46
+ class="preview"
47
+ *ngIf="selectionManager.selection.length >= 1"
48
+ [src]="lastSelected().asset.preview + '?preset=medium'"
49
+ />
50
+ </div>
51
+ <div class="card-block details" *ngIf="selectionManager.selection.length >= 1">
52
+ <div *ngIf="selectionManager.selection.length === 1">
53
+ <update-badge
54
+ [badge]="lastSelected()"
55
+ [availablePositions]="config.availablePositions"
56
+ (badgeUpdated)="onBadgeUpdated($event)"
57
+ ></update-badge>
58
+ </div>
59
+ <div *ngIf="canDelete">
60
+ <button (click)="deleteBadges(selectionManager.selection)" class="button-small mt-1">
61
+ <clr-icon shape="trash" class="is-danger"></clr-icon>
62
+ {{ 'common.delete' | translate }}
63
+ </button>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ <div class="card stack" [class.visible]="selectionManager.selection.length > 1"></div>
68
+ <div class="selection-count" [class.visible]="selectionManager.selection.length > 1">
69
+ {{
70
+ 'asset.assets-selected-count' | translate : { count: selectionManager.selection.length }
71
+ }}
72
+ <ul>
73
+ <li *ngFor="let asset of selectionManager.selection">{{ asset.name }}</li>
74
+ </ul>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </vdr-page-block>
@@ -17,6 +17,7 @@ const graphql_1 = require("./gql/graphql");
17
17
  const ngx_translate_extract_marker_1 = require("@biesbjerg/ngx-translate-extract-marker");
18
18
  const rxjs_1 = require("rxjs");
19
19
  const operators_1 = require("rxjs/operators");
20
+ const update_badge_component_1 = require("./update-badge.component");
20
21
  const getBadgeListDocument = (0, gql_1.graphql)(`
21
22
  query GetBadges($options: BadgeListOptions) {
22
23
  badges(options: $options) {
@@ -231,6 +232,8 @@ BadgeListComponent = __decorate([
231
232
  templateUrl: './badge-list.component.html',
232
233
  styleUrls: ['./badge-list.component.scss'],
233
234
  changeDetection: core_2.ChangeDetectionStrategy.OnPush,
235
+ standalone: true,
236
+ imports: [core_1.SharedModule, update_badge_component_1.UpdateBadgeComponent],
234
237
  }),
235
238
  (0, core_2.Injectable)(),
236
239
  __metadata("design:paramtypes", [core_1.NotificationService,
@@ -0,0 +1,139 @@
1
+ @import 'variables';
2
+
3
+ :host {
4
+ display: flex;
5
+ flex-direction: column;
6
+ width: 100%;
7
+ }
8
+
9
+ .gallery-wrapper {
10
+ display: flex;
11
+ flex-direction: column-reverse;
12
+ @media screen and (min-width: $breakpoint-medium) {
13
+ flex-direction: row;
14
+ }
15
+ }
16
+
17
+ .gallery {
18
+ /* autoprefixer: off */
19
+ flex: 1;
20
+ display: grid;
21
+ grid-template-columns: repeat(auto-fill, 150px);
22
+ grid-template-rows: repeat(auto-fill, 180px);
23
+ grid-gap: 10px 20px;
24
+
25
+ .card:hover {
26
+ box-shadow: 0 0.125rem 0 0 var(--color-primary-500);
27
+ border: 1px solid var(--color-primary-500);
28
+ }
29
+ }
30
+
31
+ .card {
32
+ margin-top: 0;
33
+ position: relative;
34
+ }
35
+
36
+ img.asset-thumb {
37
+ aspect-ratio: 1;
38
+ }
39
+
40
+ vdr-select-toggle {
41
+ position: absolute;
42
+ ::ng-deep .toggle {
43
+ box-shadow: 0px 5px 5px -4px rgba(0, 0, 0, 0.75);
44
+ }
45
+ top: -12px;
46
+ left: -12px;
47
+ }
48
+
49
+ .card.selected {
50
+ box-shadow: 0 0.125rem 0 0 var(--color-primary-500);
51
+ border: 1px solid var(--color-primary-500);
52
+
53
+ .selected-checkbox {
54
+ opacity: 1;
55
+ }
56
+ }
57
+
58
+ .detail {
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 4px;
62
+ font-size: 12px;
63
+ margin: 3px;
64
+ overflow: hidden;
65
+ white-space: nowrap;
66
+ text-overflow: ellipsis;
67
+ vdr-entity-info {
68
+ height: 16px;
69
+ }
70
+ }
71
+
72
+ .info-bar {
73
+ @media screen and (min-width: $breakpoint-medium) {
74
+ width: 25%;
75
+ }
76
+ padding: 0 6px;
77
+ overflow-y: visible;
78
+
79
+ .card {
80
+ z-index: 1;
81
+ }
82
+
83
+ .stack {
84
+ z-index: 0;
85
+ opacity: 0;
86
+ transform: perspective(500px) translateZ(0px) translateY(-16px);
87
+ height: 16px;
88
+ transition: transform 0.3s, opacity 0s 0.3s;
89
+ background-color: white;
90
+
91
+ &.visible {
92
+ opacity: 1;
93
+ transform: perspective(500px) translateZ(-44px) translateY(0px);
94
+ background-color: var(--color-component-bg-100);
95
+ transition: transform 0.3s, color 0.3s;
96
+ }
97
+ }
98
+
99
+ .selection-count {
100
+ opacity: 0;
101
+ position: relative;
102
+ text-align: center;
103
+ visibility: hidden;
104
+ transition: opacity 0.3s, visibility 0s 0.3s;
105
+ &.visible {
106
+ opacity: 1;
107
+ visibility: visible;
108
+ transition: opacity 0.3s, visibility 0s;
109
+ }
110
+ ul {
111
+ text-align: start;
112
+ list-style-type: none;
113
+ margin-inline-start: 12px;
114
+ li {
115
+ font-size: 12px;
116
+ }
117
+ }
118
+ }
119
+
120
+ .placeholder {
121
+ text-align: center;
122
+ color: var(--color-grey-300);
123
+ }
124
+
125
+ .preview {
126
+ img {
127
+ max-width: 100%;
128
+ }
129
+ }
130
+ .details {
131
+ font-size: 12px;
132
+ word-break: break-all;
133
+ }
134
+ .name {
135
+ line-height: 14px;
136
+ font-weight: bold;
137
+ margin-bottom: 4px;
138
+ }
139
+ }
@@ -0,0 +1,278 @@
1
+ import {
2
+ TypedBaseListComponent,
3
+ NotificationService,
4
+ ModalService,
5
+ SelectionManager,
6
+ SharedModule,
7
+ } from '@vendure/admin-ui/core'
8
+ import {
9
+ Component,
10
+ Injectable,
11
+ OnInit,
12
+ OnChanges,
13
+ ChangeDetectionStrategy,
14
+ SimpleChanges,
15
+ } from '@angular/core'
16
+ import { graphql } from './gql'
17
+ import { Badge, DeletionResult } from './gql/graphql'
18
+ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
19
+ import { EMPTY } from 'rxjs'
20
+ import { finalize, map, switchMap } from 'rxjs/operators'
21
+ import { Asset } from '@vendure/core'
22
+ import { UpdateBadgeComponent } from './update-badge.component'
23
+
24
+ const getBadgeListDocument = graphql(`
25
+ query GetBadges($options: BadgeListOptions) {
26
+ badges(options: $options) {
27
+ items {
28
+ id
29
+ createdAt
30
+ updatedAt
31
+ collection {
32
+ id
33
+ }
34
+ collectionId
35
+ position
36
+ asset {
37
+ id
38
+ name
39
+ type
40
+ mimeType
41
+ width
42
+ height
43
+ fileSize
44
+ source
45
+ preview
46
+ }
47
+ }
48
+ totalItems
49
+ }
50
+ }
51
+ `)
52
+
53
+ const createBadgeDocument = graphql(`
54
+ mutation CreateBadge($input: CreateBadgeInput!) {
55
+ createBadge(input: $input) {
56
+ id
57
+ }
58
+ }
59
+ `)
60
+
61
+ const deleteBadgeDocument = graphql(`
62
+ mutation DeleteBadge($ids: [ID!]!) {
63
+ deleteBadge(ids: $ids) {
64
+ result
65
+ message
66
+ }
67
+ }
68
+ `)
69
+
70
+ const getPluginConfigDocument = graphql(`
71
+ query GetBadgePluginConfig {
72
+ getBadgePluginConfig {
73
+ availablePositions
74
+ }
75
+ }
76
+ `)
77
+
78
+ export interface BadgePluginOptions {
79
+ availablePositions: string[]
80
+ }
81
+
82
+ @Component({
83
+ selector: 'badge-list',
84
+ templateUrl: './badge-list.component.html',
85
+ styleUrls: ['./badge-list.component.scss'],
86
+ changeDetection: ChangeDetectionStrategy.OnPush,
87
+ standalone: true,
88
+ imports: [SharedModule, UpdateBadgeComponent],
89
+ })
90
+ @Injectable()
91
+ export class BadgeListComponent
92
+ extends TypedBaseListComponent<typeof getBadgeListDocument, 'badges'>
93
+ implements OnInit, OnChanges
94
+ {
95
+ config: BadgePluginOptions
96
+ uploading = false
97
+ canDelete = true
98
+ badges: Badge[]
99
+
100
+ selectionManager = new SelectionManager<Badge>({
101
+ multiSelect: true,
102
+ itemsAreEqual: (a, b) => a.id === b.id,
103
+ additiveMode: false,
104
+ })
105
+
106
+ constructor(
107
+ private notificationService: NotificationService,
108
+ private modalService: ModalService,
109
+ ) {
110
+ super()
111
+ super.configure({
112
+ document: getBadgeListDocument,
113
+ getItems: (data) => {
114
+ this.badges = data.badges.items as Badge[]
115
+ return data.badges
116
+ },
117
+ setVariables: () => ({
118
+ options: {
119
+ skip: 0,
120
+ take: 999,
121
+ },
122
+ }),
123
+ refreshListOnChanges: [],
124
+ })
125
+
126
+ this.dataService
127
+ .query(getPluginConfigDocument)
128
+ .mapSingle((item) => item)
129
+ .subscribe({
130
+ next: (response) => {
131
+ this.config = response.getBadgePluginConfig as BadgePluginOptions
132
+ },
133
+ error: (error) => console.error('Query error:', error),
134
+ })
135
+ }
136
+
137
+ ngOnChanges(changes: SimpleChanges) {
138
+ console.log('changes:', changes)
139
+ if (this.items$) {
140
+ for (const badge of this.selectionManager.selection) {
141
+ // Update any selected assets with any changes
142
+ const match = this.badges.find((a) => a.id === badge.id)
143
+ if (match) {
144
+ Object.assign(badge, match)
145
+ }
146
+ }
147
+ }
148
+ if (changes['badges']) {
149
+ this.selectionManager.setCurrentItems(this.badges)
150
+ }
151
+ }
152
+
153
+ async ngOnInit(): Promise<void> {
154
+ super.ngOnInit()
155
+ }
156
+
157
+ toggleSelection(asset: Badge, event?: any) {
158
+ this.selectionManager.toggleSelection(asset, event)
159
+ }
160
+
161
+ selectMultiple(assets: Badge[]) {
162
+ this.selectionManager.selectMultiple(assets)
163
+ }
164
+
165
+ isSelected(asset: Badge): boolean {
166
+ return this.selectionManager.isSelected(asset)
167
+ }
168
+
169
+ lastSelected(): Badge {
170
+ return this.selectionManager.lastSelected()
171
+ }
172
+
173
+ filesSelected(files: File[]) {
174
+ if (files.length) {
175
+ this.uploading = true
176
+ this.dataService.product
177
+ .createAssets(files)
178
+ .pipe(
179
+ finalize(() => {
180
+ this.uploading = false
181
+ }),
182
+ )
183
+ .subscribe(({ createAssets }) => {
184
+ let successCount = 0
185
+ for (const result of createAssets) {
186
+ switch (result.__typename) {
187
+ case 'Asset':
188
+ successCount++
189
+ break
190
+ case 'MimeTypeError':
191
+ this.notificationService.error(result.message)
192
+ break
193
+ }
194
+ }
195
+ if (0 < successCount) {
196
+ super.refresh()
197
+ this.notificationService.success(_('badge-plugin.notify-create-badges-success'), {
198
+ count: successCount,
199
+ })
200
+ this.createBadges(createAssets as Asset[])
201
+ }
202
+ })
203
+ }
204
+ }
205
+
206
+ async createBadges(assets: Asset[]) {
207
+ for (const asset of assets) {
208
+ await this.dataService
209
+ .mutate(createBadgeDocument, {
210
+ input: {
211
+ assetId: asset.id as string,
212
+ position: this.config.availablePositions[0],
213
+ },
214
+ })
215
+ .toPromise()
216
+ }
217
+ this.refresh()
218
+ }
219
+
220
+ deleteBadges(badges: Badge[]) {
221
+ this.showModalAndDelete(badges.map((a) => a.id))
222
+ .pipe(
223
+ switchMap((response) => {
224
+ if (response.result === DeletionResult.DELETED) {
225
+ return [true]
226
+ } else {
227
+ return this.showModalAndDelete(
228
+ badges.map((a) => a.id),
229
+ response.message || '',
230
+ ).pipe(map((r) => r.result === DeletionResult.DELETED))
231
+ }
232
+ }),
233
+ )
234
+ .subscribe(
235
+ () => {
236
+ this.notificationService.success(_('common.notify-delete-success'), {
237
+ entity: 'Badges',
238
+ })
239
+ this.refresh()
240
+ this.selectionManager.clearSelection()
241
+ },
242
+ () => {
243
+ this.notificationService.error(_('common.notify-delete-error'), {
244
+ entity: 'Badges',
245
+ })
246
+ },
247
+ )
248
+ }
249
+
250
+ onBadgeUpdated() {
251
+ this.refresh()
252
+ }
253
+
254
+ private showModalAndDelete(badgeIds: string[], message?: string) {
255
+ return this.modalService
256
+ .dialog({
257
+ title: _('badge-plugin.confirm-delete-badges'),
258
+ translationVars: {
259
+ count: badgeIds.length,
260
+ },
261
+ body: message,
262
+ buttons: [
263
+ { type: 'secondary', label: _('common.cancel') },
264
+ { type: 'danger', label: _('common.delete'), returnValue: true },
265
+ ],
266
+ })
267
+ .pipe(
268
+ switchMap((res) =>
269
+ res
270
+ ? this.dataService.mutate(deleteBadgeDocument, {
271
+ ids: badgeIds,
272
+ })
273
+ : EMPTY,
274
+ ),
275
+ map((res) => res.deleteBadge),
276
+ )
277
+ }
278
+ }
@@ -0,0 +1,62 @@
1
+ /* eslint-disable */
2
+ import * as types from './graphql';
3
+ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
4
+
5
+ /**
6
+ * Map of all GraphQL operations in the project.
7
+ *
8
+ * This map has several performance disadvantages:
9
+ * 1. It is not tree-shakeable, so it will include all operations in the project.
10
+ * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
11
+ * 3. It does not support dead code elimination, so it will add unused operations.
12
+ *
13
+ * Therefore it is highly recommended to use the babel or swc plugin for production.
14
+ */
15
+ const documents = {
16
+ "\n query GetBadges($options: BadgeListOptions) {\n badges(options: $options) {\n items {\n id\n createdAt\n updatedAt\n collection {\n id\n }\n collectionId\n position\n asset {\n id\n name\n type\n mimeType\n width\n height\n fileSize\n source\n preview\n }\n }\n totalItems\n }\n }\n": types.GetBadgesDocument,
17
+ "\n mutation CreateBadge($input: CreateBadgeInput!) {\n createBadge(input: $input) {\n id\n }\n }\n": types.CreateBadgeDocument,
18
+ "\n mutation DeleteBadge($ids: [ID!]!) {\n deleteBadge(ids: $ids) {\n result\n message\n }\n }\n": types.DeleteBadgeDocument,
19
+ "\n query GetBadgePluginConfig {\n getBadgePluginConfig {\n availablePositions\n }\n }\n": types.GetBadgePluginConfigDocument,
20
+ "\n mutation UpdateBadge($input: UpdateBadgeInput!) {\n updateBadge(input: $input) {\n id\n }\n }\n": types.UpdateBadgeDocument,
21
+ };
22
+
23
+ /**
24
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
25
+ *
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
30
+ * ```
31
+ *
32
+ * The query argument is unknown!
33
+ * Please regenerate the types.
34
+ */
35
+ export function graphql(source: string): unknown;
36
+
37
+ /**
38
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
39
+ */
40
+ export function graphql(source: "\n query GetBadges($options: BadgeListOptions) {\n badges(options: $options) {\n items {\n id\n createdAt\n updatedAt\n collection {\n id\n }\n collectionId\n position\n asset {\n id\n name\n type\n mimeType\n width\n height\n fileSize\n source\n preview\n }\n }\n totalItems\n }\n }\n"): (typeof documents)["\n query GetBadges($options: BadgeListOptions) {\n badges(options: $options) {\n items {\n id\n createdAt\n updatedAt\n collection {\n id\n }\n collectionId\n position\n asset {\n id\n name\n type\n mimeType\n width\n height\n fileSize\n source\n preview\n }\n }\n totalItems\n }\n }\n"];
41
+ /**
42
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
43
+ */
44
+ export function graphql(source: "\n mutation CreateBadge($input: CreateBadgeInput!) {\n createBadge(input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation CreateBadge($input: CreateBadgeInput!) {\n createBadge(input: $input) {\n id\n }\n }\n"];
45
+ /**
46
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
47
+ */
48
+ export function graphql(source: "\n mutation DeleteBadge($ids: [ID!]!) {\n deleteBadge(ids: $ids) {\n result\n message\n }\n }\n"): (typeof documents)["\n mutation DeleteBadge($ids: [ID!]!) {\n deleteBadge(ids: $ids) {\n result\n message\n }\n }\n"];
49
+ /**
50
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
51
+ */
52
+ export function graphql(source: "\n query GetBadgePluginConfig {\n getBadgePluginConfig {\n availablePositions\n }\n }\n"): (typeof documents)["\n query GetBadgePluginConfig {\n getBadgePluginConfig {\n availablePositions\n }\n }\n"];
53
+ /**
54
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
55
+ */
56
+ export function graphql(source: "\n mutation UpdateBadge($input: UpdateBadgeInput!) {\n updateBadge(input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation UpdateBadge($input: UpdateBadgeInput!) {\n updateBadge(input: $input) {\n id\n }\n }\n"];
57
+
58
+ export function graphql(source: string) {
59
+ return (documents as any)[source] ?? {};
60
+ }
61
+
62
+ export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;