diff --git a/packages/drafts-realm/ProductList/b325edb9-6088-4db1-9629-502c42c02d70.json b/packages/drafts-realm/ProductList/b325edb9-6088-4db1-9629-502c42c02d70.json index 42db9db431..93b23663bb 100644 --- a/packages/drafts-realm/ProductList/b325edb9-6088-4db1-9629-502c42c02d70.json +++ b/packages/drafts-realm/ProductList/b325edb9-6088-4db1-9629-502c42c02d70.json @@ -39,17 +39,17 @@ }, "products.6": { "links": { - "self": "../Product/03b3e910-a7ea-4881-b2cc-a1bb738530d9" + "self": "../Product/518dbfc8-a9fa-4403-8422-885edb64063f" } }, "products.7": { "links": { - "self": "../Product/518dbfc8-a9fa-4403-8422-885edb64063f" + "self": "../Product/13e1dc95-e84d-4ddd-ad17-fa6b3c59cca5" } }, "products.8": { "links": { - "self": "../Product/13e1dc95-e84d-4ddd-ad17-fa6b3c59cca5" + "self": "../VideoProduct/9d37cb15-f63a-4eb1-ba1b-f209a12fe1c8" } } }, diff --git a/packages/drafts-realm/ProductWithVideo/03b3e910-a7ea-4881-b2cc-a1bb738530d9.json b/packages/drafts-realm/ProductWithVideo/03b3e910-a7ea-4881-b2cc-a1bb738530d9.json new file mode 100644 index 0000000000..5f1032cd3e --- /dev/null +++ b/packages/drafts-realm/ProductWithVideo/03b3e910-a7ea-4881-b2cc-a1bb738530d9.json @@ -0,0 +1,36 @@ +{ + "data": { + "type": "card", + "attributes": { + "videoUrl": "https://v.etsystatic.com/video/upload/s--nMgoUlxI--/ac_none,c_crop,du_15,h_960,q_auto:good,w_720,x_0,y_0/IMG_2082_dnw70f", + "images": [ + "https://i.etsystatic.com/8595526/r/il/b3b96c/3064849416/il_1588xN.3064849416_r41c.jpg", + "https://i.etsystatic.com/8595526/r/il/19a557/3064848658/il_1588xN.3064848658_m2t5.jpg", + "https://i.etsystatic.com/8595526/r/il/ac2b0b/3064860134/il_1588xN.3064860134_mm80.jpg", + "https://i.etsystatic.com/8595526/r/il/0e8ff6/3112592903/il_1588xN.3112592903_hq05.jpg", + "https://i.etsystatic.com/8595526/r/il/370ede/3064859840/il_1588xN.3064859840_rft0.jpg" + ], + "unitPriceCents": 10277, + "usShippingCostCents": 0, + "leadTimeDays": 14, + "deliveryWindowDays": 19, + "isReturnable": false, + "details": "This listing is a special deal. It's a HEAVILY DISCOUNTED package of the 2 busts that I make and sell separately – Marcus Aurelius and Seneca.\n\nThese busts look and feel great. Their rustic appearance is a joy to look at. The stone cold concrete is mesmerising to the touch!\n\nIn the past, my customers were buying these separately for a full price, but now you can get these two together and pay around 25% less.", + "title": "MARCUS + SENECA Premium Concrete Busts | Stoic Set", + "description": null + }, + "relationships": { + "seller": { + "links": { + "self": "../Seller/2e039829-9d63-4e06-a257-0986614d9242" + } + } + }, + "meta": { + "adoptsFrom": { + "module": "../product-with-video", + "name": "ProductWithVideo" + } + } + } +} diff --git a/packages/drafts-realm/ProductWithVideoAndRatings/03b3e910-a7ea-4881-b2cc-a1bb738530d9.json b/packages/drafts-realm/ProductWithVideoAndRatings/03b3e910-a7ea-4881-b2cc-a1bb738530d9.json new file mode 100644 index 0000000000..381ac789ae --- /dev/null +++ b/packages/drafts-realm/ProductWithVideoAndRatings/03b3e910-a7ea-4881-b2cc-a1bb738530d9.json @@ -0,0 +1,40 @@ +{ + "data": { + "type": "card", + "attributes": { + "videoUrl": "https://v.etsystatic.com/video/upload/s--nMgoUlxI--/ac_none,c_crop,du_15,h_960,q_auto:good,w_720,x_0,y_0/IMG_2082_dnw70f", + "images": [ + "https://i.etsystatic.com/8595526/r/il/b3b96c/3064849416/il_1588xN.3064849416_r41c.jpg", + "https://i.etsystatic.com/8595526/r/il/19a557/3064848658/il_1588xN.3064848658_m2t5.jpg", + "https://i.etsystatic.com/8595526/r/il/ac2b0b/3064860134/il_1588xN.3064860134_mm80.jpg", + "https://i.etsystatic.com/8595526/r/il/0e8ff6/3112592903/il_1588xN.3112592903_hq05.jpg", + "https://i.etsystatic.com/8595526/r/il/370ede/3064859840/il_1588xN.3064859840_rft0.jpg" + ], + "unitPriceCents": 10277, + "usShippingCostCents": 0, + "leadTimeDays": 14, + "deliveryWindowDays": 19, + "isReturnable": false, + "details": "This listing is a special deal. It's a HEAVILY DISCOUNTED package of the 2 busts that I make and sell separately – Marcus Aurelius and Seneca.\n\nThese busts look and feel great. Their rustic appearance is a joy to look at. The stone cold concrete is mesmerising to the touch!\n\nIn the past, my customers were buying these separately for a full price, but now you can get these two together and pay around 25% less.", + "ratingsSummary": { + "average": 4.99, + "count": 385 + }, + "title": "MARCUS + SENECA Premium Concrete Busts | Stoic Set", + "description": null + }, + "relationships": { + "seller": { + "links": { + "self": "../Seller/2e039829-9d63-4e06-a257-0986614d9242" + } + } + }, + "meta": { + "adoptsFrom": { + "module": "../product-with-video-and-ratings", + "name": "ProductWithVideoAndRatings" + } + } + } +} diff --git a/packages/drafts-realm/VideoProduct/871e0e62-9bd9-4dc6-8dfc-0abc80e9c247.json b/packages/drafts-realm/VideoProduct/871e0e62-9bd9-4dc6-8dfc-0abc80e9c247.json new file mode 100644 index 0000000000..e7b99520d0 --- /dev/null +++ b/packages/drafts-realm/VideoProduct/871e0e62-9bd9-4dc6-8dfc-0abc80e9c247.json @@ -0,0 +1,30 @@ +{ + "data": { + "type": "card", + "attributes": { + "videoUrl": null, + "images": [], + "unitPriceCents": null, + "usShippingCostCents": null, + "leadTimeDays": null, + "deliveryWindowDays": null, + "isReturnable": null, + "details": null, + "title": null, + "description": null + }, + "relationships": { + "seller": { + "links": { + "self": null + } + } + }, + "meta": { + "adoptsFrom": { + "module": "../video-product", + "name": "VideoProduct" + } + } + } +} \ No newline at end of file diff --git a/packages/drafts-realm/VideoProduct/9d37cb15-f63a-4eb1-ba1b-f209a12fe1c8.json b/packages/drafts-realm/VideoProduct/9d37cb15-f63a-4eb1-ba1b-f209a12fe1c8.json new file mode 100644 index 0000000000..c37d9d7db4 --- /dev/null +++ b/packages/drafts-realm/VideoProduct/9d37cb15-f63a-4eb1-ba1b-f209a12fe1c8.json @@ -0,0 +1,36 @@ +{ + "data": { + "type": "card", + "attributes": { + "videoUrl": "https://v.etsystatic.com/video/upload/s--nMgoUlxI--/ac_none,c_crop,du_15,h_960,q_auto:good,w_720,x_0,y_0/IMG_2082_dnw70f", + "images": [ + "https://i.etsystatic.com/8595526/r/il/b3b96c/3064849416/il_1588xN.3064849416_r41c.jpg", + "https://i.etsystatic.com/8595526/r/il/19a557/3064848658/il_1588xN.3064848658_m2t5.jpg", + "https://i.etsystatic.com/8595526/r/il/ac2b0b/3064860134/il_1588xN.3064860134_mm80.jpg", + "https://i.etsystatic.com/8595526/r/il/0e8ff6/3112592903/il_1588xN.3112592903_hq05.jpg", + "https://i.etsystatic.com/8595526/r/il/370ede/3064859840/il_1588xN.3064859840_rft0.jpg" + ], + "unitPriceCents": 10277, + "usShippingCostCents": 0, + "leadTimeDays": 14, + "deliveryWindowDays": 19, + "isReturnable": false, + "details": "Thislisting is a special deal. It's a HEAVILY DISCOUNTED package of the 2 busts that I make and sell separately – Marcus Aurelius and Seneca.\n\nThese busts look and feel great. Their rustic appearance is a joy to look at. The stone cold concrete is mesmerising to the touch!\n\nIn the past, my customers were buying these separately for a full price, but now you can get these two together and pay around 25% less.", + "title": "MARCUS + SENECA Premium Concrete Busts | Stoic Set", + "description": null + }, + "relationships": { + "seller": { + "links": { + "self": "../Seller/2e039829-9d63-4e06-a257-0986614d9242" + } + } + }, + "meta": { + "adoptsFrom": { + "module": "../video-product", + "name": "VideoProduct" + } + } + } +} \ No newline at end of file diff --git a/packages/drafts-realm/product-list-with-filter.gts b/packages/drafts-realm/product-list-with-filter.gts new file mode 100644 index 0000000000..0f6b6493a0 --- /dev/null +++ b/packages/drafts-realm/product-list-with-filter.gts @@ -0,0 +1,230 @@ +import { + CardDef, + field, + linksToMany, +} from 'https://cardstack.com/base/card-api'; +import { Component } from 'https://cardstack.com/base/card-api'; +import { + Product as ProductCard, + formatUsd, + EmbeddedProductComponent, +} from './product'; +import GlimmerComponent from '@glimmer/component'; +import { fn } from '@ember/helper'; +import { on } from '@ember/modifier'; +import { BoxelInput } from '@cardstack/boxel-ui/components'; +// @ts-ignore TS1206: Decorators are not valid here. +import { action } from '@ember/object'; +// @ts-ignore TS1206: Decorators are not valid here. +import { tracked } from '@glimmer/tracking'; + +interface FeaturedProductComponentSignature { + Args: { + model: ProductCard | undefined; + viewProduct: (arg0: ProductCard | undefined) => void; + }; +} + +class FeaturedProductComponent extends GlimmerComponent { + +} + +export class ProductList extends CardDef { + @field products = linksToMany(ProductCard); + static displayName = 'Product List'; + + static isolated = class Isolated extends Component { + // @ts-ignore TS1206: Decorators are not valid here. + @tracked filterText = ''; + + // @ts-ignore TS1206: Decorators are not valid here. + @action + updateFilter(event: Event) { + this.filterText = (event.target as any).value.toLowerCase(); + } + + get filteredProducts() { + let { filterText } = this; + if (!filterText) return this.args.model.products; + return this.args.model.products?.filter((product) => { + return product.title?.toLowerCase().includes(filterText); + }); + } + + get featuredProduct() { + return this.filteredProducts?.[0]; + } + + get productsForGrid() { + return this.filteredProducts?.slice(1) || []; + } + + // @ts-ignore TS1206: Decorators are not valid here. + @action + viewProduct(model: ProductCard | undefined) { + if (model && this.args.context?.actions?.viewCard) { + this.args.context.actions.viewCard(model); + } else { + console.warn( + 'Product card opening functionality is not available here.', + ); + } + } + + + }; + + /* + + static embedded = class Embedded extends Component { + + } + + static atom = class Atom extends Component { + + } + + static edit = class Edit extends Component { + + } + + + + + + */ +} diff --git a/packages/drafts-realm/product-list.gts b/packages/drafts-realm/product-list.gts index fe0b9724a0..9e1083b25f 100644 --- a/packages/drafts-realm/product-list.gts +++ b/packages/drafts-realm/product-list.gts @@ -12,10 +12,9 @@ import { import GlimmerComponent from '@glimmer/component'; import { fn } from '@ember/helper'; import { on } from '@ember/modifier'; -// @ts-ignore TS1206: Decorators are not valid here. import { action } from '@ember/object'; -// @ts-ignore TS1206: Decorators are not valid here. import { tracked } from '@glimmer/tracking'; +import { BoxelInput } from '@cardstack/boxel-ui/components'; interface FeaturedProductComponentSignature { Args: { @@ -94,94 +93,118 @@ class FeaturedProductComponent extends GlimmerComponent } -export class ProductList extends CardDef { - @field products = linksToMany(ProductCard); - static displayName = 'Product List'; +class Isolated extends Component { + get featuredProduct() { + return this.filteredProducts?.[0]; + } - static isolated = class Isolated extends Component { - get featuredProduct() { - return this.args.model.products?.[0]; - } + get productsForGrid() { + return this.filteredProducts?.slice(1) || []; + } - get productsForGrid() { - return this.args.model.products?.slice(1) || []; - } + get filteredProducts() { + let allProducts = this.args.model.products || []; + let { filterText } = this; + if (!filterText) return allProducts; + return allProducts.filter((product) => { + return product.title.toLowerCase().includes(filterText); + }); + } - // @ts-ignore TS1206: Decorators are not valid here. - @action - viewProduct(model: ProductCard | undefined) { - if (model && this.args.context?.actions?.viewCard) { - this.args.context.actions.viewCard(model); - } else { - console.warn( - 'Product card opening functionality is not available here.', - ); - } + // @ts-ignore TS1206: Decorators are not valid here. + @action + viewProduct(model: ProductCard | undefined) { + if (model && this.args.context?.actions?.viewCard) { + this.args.context.actions.viewCard(model); + } else { + console.warn('Product card opening functionality is not available here.'); } + } - +} + +export class ProductList extends CardDef { + @field products = linksToMany(ProductCard); + static displayName = 'Product List'; + + static isolated = Isolated; /* @@ -203,5 +226,8 @@ export class ProductList extends CardDef { + + + */ } diff --git a/packages/drafts-realm/product-with-video-and-ratings.gts b/packages/drafts-realm/product-with-video-and-ratings.gts new file mode 100644 index 0000000000..7c6504d10f --- /dev/null +++ b/packages/drafts-realm/product-with-video-and-ratings.gts @@ -0,0 +1,139 @@ +import { Product, ProductDetail, ProductImages, formatUsd } from './product'; +import { + Component, + field, + contains, + StringField, +} from 'https://cardstack.com/base/card-api'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { RatingsSummary as RatingsSummaryField } from './ratings-summary'; + +class Isolated extends Component { + @tracked activeImage = this.args.model.images?.[0]; + + @action updateActiveImage(image: string) { + this.activeImage = image; + } + + +} + +// @ts-ignore +export class ProductWithVideoAndRatings extends Product { + static displayName = 'Product with Video and Ratings'; + @field videoUrl = contains(StringField); + @field ratingsSummary = contains(RatingsSummaryField, { + computeVia(this: ProductWithVideoAndRatings) { + return { + average: Math.floor(Math.random() * 6), // random number between 0 and 5 inclusive + count: Math.floor(Math.random() * 29701) + 300, // random number between 300 and 30000 + }; + }, + }); + static isolated = Isolated; +} diff --git a/packages/drafts-realm/product-with-video.gts b/packages/drafts-realm/product-with-video.gts new file mode 100644 index 0000000000..7b6ed4e7e9 --- /dev/null +++ b/packages/drafts-realm/product-with-video.gts @@ -0,0 +1,130 @@ +import { Product, ProductDetail, ProductImages, formatUsd } from './product'; +import { + Component, + field, + contains, + StringField, +} from 'https://cardstack.com/base/card-api'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; + +// https://v.etsystatic.com/video/upload/s--nMgoUlxI--/ac_none,c_crop,du_15,h_960,q_auto:good,w_720,x_0,y_0/IMG_2082_dnw70f + +class Isolated extends Component { + @tracked activeImage = this.args.model.images?.[0]; + + @action updateActiveImage(image: string) { + this.activeImage = image; + } + + +} + +// @ts-ignore +export class ProductWithVideo extends Product { + static displayName = 'Product with Video'; + @field videoUrl = contains(StringField); + static isolated = Isolated; +} diff --git a/packages/drafts-realm/video-product.gts b/packages/drafts-realm/video-product.gts new file mode 100644 index 0000000000..fd68e60563 --- /dev/null +++ b/packages/drafts-realm/video-product.gts @@ -0,0 +1,139 @@ +import { Product, ProductDetail, ProductImages, formatUsd } from './product'; +import { + Component, + field, + contains, + StringField, +} from 'https://cardstack.com/base/card-api'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { RatingsSummary as RatingsSummaryField } from './ratings-summary'; + +class Isolated extends Component { + @tracked activeImage = this.args.model.images?.[0]; + + @action updateActiveImage(image: string) { + this.activeImage = image; + } + + +} + +// @ts-ignore +export class VideoProduct extends Product { + static displayName = 'Video Product'; + @field videoUrl = contains(StringField); + @field ratingsSummary = contains(RatingsSummaryField, { + computeVia(this: VideoProduct) { + return new RatingsSummaryField({ + average: Math.floor(Math.random() * 6), // random number between 0 and 5 inclusive + count: Math.floor(Math.random() * 29701) + 300, // random number between 300 and 30000 + }); + }, + }); + static isolated = Isolated; +}