Skip to content

Commit

Permalink
feat(experience): Added data list component (#1050)
Browse files Browse the repository at this point in the history
The data list component can be used to render a list of components for a given entity. Each data item is wrapped and supports a link to the entity. The components rendered for the item are based on the composition components.

closes: [HRZ-90985](https://spryker.atlassian.net/browse/HRZ-90985)

[HRZ-90985]:
https://spryker.atlassian.net/browse/HRZ-90985?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

---------

Co-authored-by: dunqan <[email protected]>
  • Loading branch information
tobi-or-not-tobi and dunqan authored Jan 15, 2024
1 parent dab4da1 commit 1464fc9
Show file tree
Hide file tree
Showing 33 changed files with 433 additions and 27 deletions.
15 changes: 9 additions & 6 deletions apps/storefront/vite.config.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ export const viteConfig = {
index: './client',
ssr: './server',
},
plugins: (): Plugin[] => [
checker({
typescript: {
tsconfigPath: 'tsconfig.app.json',
},
}),
plugins: (config?): Plugin[] => [
config?.mode === 'production'
? ({} as unknown as Plugin)
: checker({
typescript: {
tsconfigPath: 'tsconfig.app.json',
},
}),

tsconfigPaths({ root: viteConfig.monorepoRoot }) as unknown as Plugin,
],
};
6 changes: 3 additions & 3 deletions apps/storefront/vite.config.dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { join } from 'path';
import { defineConfig } from 'vite';
import { viteConfig } from './vite.config.common.js';

export default defineConfig({
export default defineConfig((config) => ({
root: viteConfig.index,
envDir: viteConfig.root,
envPrefix: viteConfig.envPrefix,
Expand All @@ -19,5 +19,5 @@ export default defineConfig({
},
define: viteConfig.define,
publicDir: '../../../libs/template/presets/public',
plugins: [...viteConfig.plugins()],
});
plugins: [...viteConfig.plugins(config)],
}));
6 changes: 3 additions & 3 deletions apps/storefront/vite.config.netlify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { join } from 'path';
import { defineConfig } from 'vite';
import { viteConfig } from './vite.config.common.js';

export default defineConfig({
export default defineConfig((config) => ({
root: viteConfig.index,
define: viteConfig.define,
build: {
Expand All @@ -21,5 +21,5 @@ export default defineConfig({
external: ['fs', 'path', 'url', 'module', 'vm', /^node/, /^@netlify/],
},
},
plugins: [...viteConfig.plugins()],
});
plugins: [...viteConfig.plugins(config)],
}));
6 changes: 3 additions & 3 deletions apps/storefront/vite.config.prod-no-ssr.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig } from 'vite';
import { viteConfig } from './vite.config.common.js';

export default defineConfig({
export default defineConfig((config) => ({
root: viteConfig.index,
envDir: viteConfig.root,
envPrefix: viteConfig.envPrefix,
Expand All @@ -14,5 +14,5 @@ export default defineConfig({
},
define: viteConfig.define,
publicDir: '../../../libs/template/presets/public',
plugins: [...viteConfig.plugins()],
});
plugins: [...viteConfig.plugins(config)],
}));
4 changes: 2 additions & 2 deletions apps/storefront/vite.config.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { join } from 'path';
import { defineConfig, UserConfig } from 'vite';
import { viteConfig } from './vite.config.common.js';

export default defineConfig(() => {
export default defineConfig((config) => {
return {
root: viteConfig.index,
envDir: viteConfig.root,
Expand Down Expand Up @@ -36,6 +36,6 @@ export default defineConfig(() => {
noExternal: true,
},
define: viteConfig.define,
plugins: [...viteConfig.plugins()],
plugins: [...viteConfig.plugins(config)],
} as UserConfig;
});
2 changes: 1 addition & 1 deletion apps/storefront/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export default defineConfig((config) => {
emptyOutDir: true,
},
publicDir: '../../../libs/template/presets/public',
plugins: [...viteConfig.plugins(), splitVendorChunkPlugin()],
plugins: [...viteConfig.plugins(config), splitVendorChunkPlugin()],
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import {
ApiMerchantModel,
Merchant,
MerchantAdapter,
MerchantListNormalizer,
MerchantListQualifier,
MerchantNormalizer,
MerchantQualifier,
} from '@spryker-oryx/merchant';

import { Observable } from 'rxjs';

export class DefaultMerchantAdapter implements MerchantAdapter {
Expand All @@ -19,13 +22,22 @@ export class DefaultMerchantAdapter implements MerchantAdapter {
) {}

get({ id }: MerchantQualifier): Observable<Merchant> {
const include = ['merchant-opening-hours', 'merchant-addresses'];
const includes = ['merchant-opening-hours', 'merchant-addresses'];
return this.http
.get<ApiMerchantModel.Merchant>(
`${this.SCOS_BASE_URL}/${this.merchantEndpoint}/${id}${
include?.length ? '?include=' : ''
}${include?.join(',') || ''}`
includes?.length ? '?include=' : ''
}${includes?.join(',') || ''}`
)
.pipe(this.transformer.do(MerchantNormalizer));
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
getList(qualifier?: MerchantListQualifier): Observable<Merchant[]> {
return this.http
.get<ApiMerchantModel.Merchant[]>(
`${this.SCOS_BASE_URL}/${this.merchantEndpoint}`
)
.pipe(this.transformer.do(MerchantListNormalizer));
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './merchant-list.normalizer';
export * from './merchant.normalizer';
export * from './models';
export * from './offer.normalizer';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TransformerService } from '@spryker-oryx/core';
import {
ApiMerchantModel,
Merchant,
MerchantNormalizer,
} from '@spryker-oryx/merchant';
import { Observable, combineLatest, of } from 'rxjs';

export function merchantListNormalizer(
data: ApiMerchantModel.Merchant[],
transformer: TransformerService
): Observable<Merchant[]> {
return data.length
? combineLatest(
data.map((cart) => transformer.transform(cart, MerchantNormalizer))
)
: of([]);
}
9 changes: 9 additions & 0 deletions libs/domain/merchant/services/src/default-merchant.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { injectQuery, QueryState } from '@spryker-oryx/core';
import {
Merchant,
MerchantListQualifier,
MerchantListQuery,
MerchantQualifier,
MerchantQuery,
MerchantService,
Expand All @@ -11,11 +13,18 @@ export class DefaultMerchantService implements MerchantService {
protected merchantQuery = injectQuery<Merchant, MerchantQualifier>(
MerchantQuery
);
protected merchantListQuery = injectQuery<Merchant[], MerchantListQualifier>(
MerchantListQuery
);

get(qualifier: MerchantQualifier): Observable<Merchant | undefined> {
return this.merchantQuery.get(qualifier);
}

getList(qualifier?: MerchantQualifier): Observable<Merchant[] | undefined> {
return this.merchantListQuery.get(qualifier);
}

getState(qualifier: MerchantQualifier): Observable<QueryState<Merchant>> {
return this.merchantQuery.getState(qualifier);
}
Expand Down
3 changes: 2 additions & 1 deletion libs/domain/merchant/src/models/merchant.model.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export interface MerchantQualifier {
id?: string;
scope?: string;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface MerchantListQualifier {}

export interface Merchant {
id: string;
Expand Down
10 changes: 9 additions & 1 deletion libs/domain/merchant/src/services/adapter/merchant.adapter.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import { Transformer } from '@spryker-oryx/core';
import { Observable } from 'rxjs';
import { Merchant, MerchantQualifier, ProductOffer } from '../../models';
import {
Merchant,
MerchantListQualifier,
MerchantQualifier,
ProductOffer,
} from '../../models';

export const MerchantAdapter = 'oryx.MerchantAdapter';
export const MerchantNormalizer = 'oryx.MerchantNormalizer*';
export const MerchantListNormalizer = 'oryx.MerchantListNormalizer*';

export const OfferNormalizer = 'oryx.OfferNormalizer*';

export interface MerchantAdapter {
get(qualifier: MerchantQualifier): Observable<Merchant>;
getList(qualifier?: MerchantListQualifier): Observable<Merchant[]>;
}

declare global {
interface InjectionTokensContractMap {
[MerchantAdapter]: MerchantAdapter;
[MerchantNormalizer]: Transformer<Merchant>;
[MerchantListNormalizer]: Transformer<Merchant[]>;
[OfferNormalizer]: Transformer<ProductOffer>;
}
}
5 changes: 4 additions & 1 deletion libs/domain/merchant/src/services/merchant.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { QueryState } from '@spryker-oryx/core';
import { Observable } from 'rxjs';
import { Merchant, MerchantQualifier } from '../models';
import { Merchant, MerchantListQualifier, MerchantQualifier } from '../models';

export interface MerchantService {
get(qualifier: MerchantQualifier): Observable<Merchant | undefined>;
getList(
qualifier?: MerchantListQualifier
): Observable<Merchant[] | undefined>;
getState(qualifier: MerchantQualifier): Observable<QueryState<Merchant>>;
}

Expand Down
7 changes: 7 additions & 0 deletions libs/domain/merchant/src/services/providers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { provideEntity } from '@spryker-oryx/core';
import { Provider } from '@spryker-oryx/di';
import { provideExperienceData } from '@spryker-oryx/experience';
import { merchantListNormalizer } from '@spryker-oryx/merchant/services';
import { MERCHANT } from '../entity';
import {
merchantHeaderNavigation,
Expand All @@ -10,6 +11,7 @@ import {
} from '../presets';
import {
MerchantAdapter,
MerchantListNormalizer,
MerchantNormalizer,
OfferNormalizer,
merchantIncludes,
Expand Down Expand Up @@ -66,6 +68,11 @@ export const merchantProviders: Provider[] = [
(m) => m.merchantNormalizer
),
},

{
provide: MerchantListNormalizer,
useValue: merchantListNormalizer,
},
...merchantQueries,
...merchantsEffects,
...merchantIncludes,
Expand Down
2 changes: 1 addition & 1 deletion libs/domain/merchant/src/services/state/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { MerchantQuery } from './queries';
function setMerchant(query: QueryService, offer: ProductOffer) {
query.getQuery<MerchantQuery>(MerchantQuery)?.set({
data: offer.merchant,
qualifier: { id: offer.merchant.id, scope: 'minimal' },
qualifier: { id: offer.merchant.id },
});
}

Expand Down
13 changes: 12 additions & 1 deletion libs/domain/merchant/src/services/state/queries.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import { provideQuery, Query } from '@spryker-oryx/core';
import { inject } from '@spryker-oryx/di';
import { LocaleChanged } from '@spryker-oryx/i18n';
import { Merchant, MerchantQualifier } from '../../models';
import {
Merchant,
MerchantListQualifier,
MerchantQualifier,
} from '../../models';
import { MerchantAdapter } from '../adapter';

export const MerchantQuery = 'oryx.merchantQuery';
export const MerchantListQuery = 'oryx.merchantListQuery';

export type MerchantQuery = Query<Merchant, MerchantQualifier>;
export type MerchantListQuery = Query<Merchant[], MerchantListQuery>;

export const merchantQueries = [
provideQuery(MerchantQuery, (adapter = inject(MerchantAdapter)) => ({
loader: (q: MerchantQualifier) => adapter.get(q),
refreshOn: [LocaleChanged],
})),

provideQuery(MerchantListQuery, (adapter = inject(MerchantAdapter)) => ({
loader: (q: MerchantListQualifier) => adapter.getList(q),
refreshOn: [LocaleChanged],
})),
];
57 changes: 57 additions & 0 deletions libs/platform/experience/data-list/data-list.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
ContextController,
EntityContext,
EntityService,
} from '@spryker-oryx/core';
import { resolve } from '@spryker-oryx/di';
import { ContentMixin, LayoutMixin } from '@spryker-oryx/experience';
import {
computed,
elementEffect,
hydrate,
signalAware,
} from '@spryker-oryx/utilities';
import { LitElement, TemplateResult, html } from 'lit';
import { repeat } from 'lit/directives/repeat.js';
import { of } from 'rxjs';
import { DataListOptions } from './data-list.model';

@hydrate()
@signalAware()
export class DataListComponent extends LayoutMixin(
ContentMixin<DataListOptions>(LitElement)
) {
protected contextController: ContextController = new ContextController(this);

@elementEffect()
protected setContext = (): void => {
this.contextController.provide(EntityContext, this.$options().entity);
};

protected entityService = resolve(EntityService);

protected $list = computed(() =>
this.$options().entity
? this.entityService.getListQualifiers({ type: this.$options().entity })
: of([]).pipe()
);

protected override render(): TemplateResult | void {
const list = this.$list();

if (!list?.length) return;

return this.renderLayout({
template: html`${repeat(
list,
(item) =>
html`<oryx-data-wrapper
.options=${{ link: this.$options().link }}
.qualifier=${item}
>
<oryx-composition .uid=${this.uid}></oryx-composition>
</oryx-data-wrapper>`
)}`,
});
}
}
7 changes: 7 additions & 0 deletions libs/platform/experience/data-list/data-list.def.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { componentDef } from '@spryker-oryx/utilities';

export const dataList = componentDef({
name: 'oryx-data-list',
impl: () => import('./data-list.component').then((m) => m.DataListComponent),
schema: () => import('./data-list.schema').then((m) => m.dataListSchema),
});
4 changes: 4 additions & 0 deletions libs/platform/experience/data-list/data-list.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface DataListOptions {
entity?: string;
link?: boolean;
}
7 changes: 7 additions & 0 deletions libs/platform/experience/data-list/data-list.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ContentComponentSchema } from '@spryker-oryx/experience';
import { DataListComponent } from './data-list.component';

export const dataListSchema: ContentComponentSchema<DataListComponent> = {
name: 'Data list',
group: 'Experience',
};
3 changes: 3 additions & 0 deletions libs/platform/experience/data-list/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './data-list.component';
export * from './data-list.model';
export * from './data-list.schema';
Loading

0 comments on commit 1464fc9

Please sign in to comment.