Skip to content

Commit 1eaf19c

Browse files
committed
Editor product selector and serialization.
1 parent 8ab5800 commit 1eaf19c

File tree

7 files changed

+248
-34
lines changed

7 files changed

+248
-34
lines changed

src/Umbraco.Cms.Integrations.Commerce.Shopify/App_Plugins/UmbracoCms.Integrations/Commerce/Shopify/js/productPicker.controller.js

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,111 @@
1-
function ProductPickerController($scope, umbracoCmsIntegrationsCommerceShopifyResource) {
1+
function ProductPickerController($scope, editorService, notificationsService, umbracoCmsIntegrationsCommerceShopifyService, umbracoCmsIntegrationsCommerceShopifyResource) {
2+
3+
const oauthName = "OAuth";
24

35
var vm = this;
46

5-
umbracoCmsIntegrationsCommerceShopifyResource.getProductsList().then(function(response) {
6-
console.log(response);
7+
vm.loading = false;
8+
vm.selectedProducts = [];
9+
10+
// step 1. check configuration
11+
checkConfiguration(function() {
12+
// step 2. get products
13+
vm.loading = true;
14+
umbracoCmsIntegrationsCommerceShopifyResource.getProductsList().then(function (response) {
15+
if (response.isValid) {
16+
vm.productsList = response.result.products;
17+
18+
if ($scope.model.value != undefined && $scope.model.value.length > 0) {
19+
loadProductsPreview();
20+
};
21+
}
22+
vm.loading = false;
23+
});
724
});
825

26+
vm.selectProduct = function (item) {
27+
if ($scope.model.selectedProducts.filter(function (i) { return i.id === item.id }).length > 0) {
28+
$scope.model.selectedProducts = $scope.model.selectedProducts.filter(function (i) { return i.id !== item.id; });
29+
}
30+
else {
31+
$scope.model.selectedProducts.push(item);
32+
}
33+
}
34+
35+
vm.isSelected = function (item, products) {
36+
return products.filter(function (i) { return i.id === item.id }).length > 0;
37+
}
38+
39+
vm.openProductsPickerOverlay = function () {
40+
var options = {
41+
title: "Shopify products",
42+
description: "Select product(s)",
43+
selectedProducts: vm.selectedProducts,
44+
view: "/App_Plugins/UmbracoCms.Integrations/Commerce/Shopify/views/productPickerOverlay.html",
45+
size: "medium",
46+
submit: function (selectedProducts) {
47+
vm.submit(selectedProducts);
48+
49+
loadProductsPreview();
50+
51+
editorService.close();
52+
},
53+
close: function () {
54+
editorService.close();
55+
}
56+
};
57+
58+
editorService.open(options);
59+
}
60+
61+
vm.submit = function(products) {
62+
$scope.model.value = products.map(function (item) { return item.id }).join(',');
63+
}
64+
65+
vm.remove = function (node) {
66+
vm.submit(vm.selectedProducts.filter(el => el.id != node.alias));
67+
loadProductsPreview();
68+
}
69+
70+
function checkConfiguration(callback) {
71+
umbracoCmsIntegrationsCommerceShopifyResource.checkConfiguration().then(function (response) {
72+
73+
vm.status = {
74+
isValid: response.isValid === true,
75+
type: response.type,
76+
description: umbracoCmsIntegrationsCommerceShopifyService.configDescription[response.type.value],
77+
useOAuth: response.isValid === true && response.type.value === oauthName
78+
};
79+
80+
if (response.isValid === false) {
81+
vm.loading = false;
82+
vm.error = umbracoCmsIntegrationsCommerceShopifyService.configDescription.None;
83+
notificationsService.warning("Shopify API", umbracoCmsIntegrationsCommerceShopifyService.configDescription.None);
84+
} else {
85+
callback();
86+
}
87+
});
88+
}
89+
90+
function loadProductsPreview() {
91+
vm.previewNodes = [];
92+
93+
var ids = $scope.model.value.split(",");
94+
95+
var list = vm.productsList.filter(el => {
96+
var id = ids.find(e => e == el.id);
97+
return id !== undefined ? el : null;
98+
});
99+
vm.selectedProducts = list;
100+
101+
list.forEach(el => {
102+
vm.previewNodes.push({
103+
icon: "icon-shopping-basket",
104+
name: el.title,
105+
alias: el.id
106+
});
107+
});
108+
}
9109
}
10110

11111
angular.module("umbraco")
Original file line numberDiff line numberDiff line change
@@ -1 +1,26 @@
1-
<p>Hello, world!</p>
1+
<div ng-controller="Umbraco.Cms.Integrations.Commerce.Shopify.ProductPickerController as vm">
2+
3+
<div ui-sortable ng-model="vm.previewNodes" ng-if="vm.previewNodes">
4+
<umb-node-preview ng-repeat="node in vm.previewNodes"
5+
icon="node.icon"
6+
name="node.name"
7+
alias="node.alias"
8+
published="node.published"
9+
description="node.description"
10+
sortable="true"
11+
allow-remove="true"
12+
allow-open="false"
13+
on-remove="vm.remove(node)">
14+
</umb-node-preview>
15+
</div>
16+
17+
<button type="button"
18+
class="umb-node-preview-add"
19+
ng-click="vm.openProductsPickerOverlay()"
20+
id="{{model.alias}}"
21+
aria-label="{{model.label}}: {{labels.general_add}}">
22+
<localize key="general_add">Add</localize>
23+
<span class="sr-only">...</span>
24+
</button>
25+
26+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<div ng-controller="Umbraco.Cms.Integrations.Commerce.Shopify.ProductPickerController as vm">
2+
<umb-editor-view>
3+
<umb-editor-container>
4+
<umb-box>
5+
<umb-box-header title="{{ model.title }}" description="{{ model.description }}"></umb-box-header>
6+
<umb-box-content>
7+
<umb-load-indicator ng-show="vm.loading"></umb-load-indicator>
8+
<div class="umb-table" ng-if="!vm.loading">
9+
<div class="umb-table-head">
10+
<div class="umb-table-row">
11+
<div class="umb-table-cell"></div>
12+
<div class="umb-table-cell umb-table__name">
13+
<button type="button"
14+
class="umb-table-head__link sortable"
15+
ng-click="vm.sort('Title')">
16+
<localize key="general_name">Name</localize>
17+
<i class="umb-table-head__icon icon" aria-hidden="true"
18+
ng-class="{'icon-navigation-up': vm.isSortDirection('Title', 'asc'), 'icon-navigation-down': vm.isSortDirection('Title', 'desc')}"></i>
19+
</button>
20+
</div>
21+
<div class="umb-table-cell">
22+
<span>Body</span>
23+
</div>
24+
<div class="umb-table-cell">
25+
<span>Status</span>
26+
</div>
27+
<div class="umb-table-cell">
28+
<span>Price</span>
29+
</div>
30+
</div>
31+
</div>
32+
<div class="umb-table-body">
33+
<div class="umb-table-row -selectable umb-outline"
34+
ng-repeat="product in vm.productsList"
35+
ng-class="{'-selected':vm.isSelected(product, model.selectedProducts)}"
36+
ng-click="vm.selectProduct(product, $index, $event)">
37+
<div class="umb-table-cell">
38+
<img ng-src="{{ product.image.src }}" alt="{{ product.title }}" />
39+
</div>
40+
<div class="umb-table-cell umb-table__name">
41+
{{ product.title }}
42+
</div>
43+
<div class="umb-table-cell">
44+
<span>{{ product.body_html }}</span>
45+
</div>
46+
<div class="umb-table-cell">
47+
<span>{{ product.status }}</span>
48+
</div>
49+
<div class="umb-table-cell">
50+
<span>{{ product.variants[0].price }}</span>
51+
</div>
52+
</div>
53+
</div>
54+
</div>
55+
56+
<div class="flex justify-center" ng-show="!vm.loading">
57+
<umb-pagination page-number="vm.pagination.pageNumber"
58+
total-pages="vm.pagination.totalPages"
59+
on-next="vm.nextPage"
60+
on-prev="vm.prevPage"
61+
on-change="vm.changePage"
62+
on-go-to-page="vm.goToPage">
63+
</umb-pagination>
64+
</div>
65+
66+
<!-- If list is empty, then display -->
67+
<umb-empty-state ng-if="!vm.productsList"
68+
position="center">
69+
<localize key="content_listViewNoItems">There are no products in the list.</localize>
70+
</umb-empty-state>
71+
</umb-box-content>
72+
</umb-box>
73+
</umb-editor-container>
74+
<umb-editor-footer>
75+
<umb-editor-footer-content-right>
76+
<umb-button type="button"
77+
button-style="success"
78+
label-key="general_submit"
79+
shortcut="ctrl+s"
80+
action="model.submit(model.selectedProducts)">
81+
</umb-button>
82+
<umb-button type="button"
83+
button-style="link"
84+
label-key="general_close"
85+
shortcut="esc"
86+
action="model.close()">
87+
</umb-button>
88+
</umb-editor-footer-content-right>
89+
</umb-editor-footer>
90+
</umb-editor-view>
91+
92+
</div>

src/Umbraco.Cms.Integrations.Commerce.Shopify/Controllers/ProductsController.cs

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,7 @@ public ProductsController(ILogger logger, IAppSettings appSettings, ITokenServic
4848
[HttpGet]
4949
public EditorSettings CheckConfiguration()
5050
{
51-
if (string.IsNullOrEmpty(AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyShop])
52-
|| string.IsNullOrEmpty(AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyApiVersion]))
53-
return new EditorSettings();
54-
55-
return
56-
!string.IsNullOrEmpty(AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyAccessToken])
57-
? new EditorSettings { IsValid = true, Type = ConfigurationType.Api }
58-
: !string.IsNullOrEmpty(OAuthClientId)
59-
&& !string.IsNullOrEmpty(OAuthProxyBaseUrl)
60-
&& !string.IsNullOrEmpty(OAuthProxyEndpoint)
61-
? new EditorSettings { IsValid = true, Type = ConfigurationType.OAuth }
62-
: new EditorSettings();
51+
return GetConfiguration();
6352
}
6453

6554
[HttpGet]
@@ -115,7 +104,13 @@ public async Task<string> GetAccessToken([FromBody] OAuthRequestDto authRequestD
115104

116105
public async Task<ResponseDto<ProductsListDto>> GetList()
117106
{
118-
var accessToken = AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyAccessToken];
107+
string accessToken;
108+
if(GetConfiguration().Type == ConfigurationType.OAuth)
109+
TokenService.TryGetParameters(AccessTokenDbKey, out accessToken);
110+
else
111+
{
112+
accessToken = AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyAccessToken];
113+
}
119114

120115
if (string.IsNullOrEmpty(accessToken))
121116
{
@@ -143,8 +138,6 @@ public async Task<ResponseDto<ProductsListDto>> GetList()
143138

144139
if (response.IsSuccessStatusCode)
145140
{
146-
147-
148141
var result = await response.Content.ReadAsStringAsync();
149142
return new ResponseDto<ProductsListDto>
150143
{
@@ -156,23 +149,20 @@ public async Task<ResponseDto<ProductsListDto>> GetList()
156149
return new ResponseDto<ProductsListDto>();
157150
}
158151

159-
public async Task<ResponseDto<ProductsListDto>> GetListOAuth()
152+
private EditorSettings GetConfiguration()
160153
{
161-
TokenService.TryGetParameters(AccessTokenDbKey, out string accessToken);
162-
if (string.IsNullOrEmpty(accessToken))
163-
{
164-
ApiLogger.Info<ProductsController>("Cannot access Shopify - Access Token is missing.");
165-
166-
return new ResponseDto<ProductsListDto>();
167-
}
168-
169-
var requestMessage = new HttpRequestMessage
170-
{
171-
Method = HttpMethod.Get,
172-
RequestUri = new Uri("")
173-
};
154+
if (string.IsNullOrEmpty(AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyShop])
155+
|| string.IsNullOrEmpty(AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyApiVersion]))
156+
return new EditorSettings();
174157

175-
return new ResponseDto<ProductsListDto>();
158+
return
159+
!string.IsNullOrEmpty(AppSettings[Constants.UmbracoCmsIntegrationsCommerceShopifyAccessToken])
160+
? new EditorSettings { IsValid = true, Type = ConfigurationType.Api }
161+
: !string.IsNullOrEmpty(OAuthClientId)
162+
&& !string.IsNullOrEmpty(OAuthProxyBaseUrl)
163+
&& !string.IsNullOrEmpty(OAuthProxyEndpoint)
164+
? new EditorSettings { IsValid = true, Type = ConfigurationType.OAuth }
165+
: new EditorSettings();
176166
}
177167
}
178168
}

src/Umbraco.Cms.Integrations.Commerce.Shopify/Models/Dtos/ProductDto.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ namespace Umbraco.Cms.Integrations.Commerce.Shopify.Models.Dtos
66
{
77
public class ProductDto
88
{
9+
[JsonProperty("id")]
10+
public long Id { get; set; }
11+
912
[JsonProperty("title")]
1013
public string Title { get; set; }
1114

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
using System.Collections.Generic;
22

3+
using Newtonsoft.Json;
4+
35
namespace Umbraco.Cms.Integrations.Commerce.Shopify.Models.Dtos
46
{
57
public class ProductsListDto
68
{
9+
[JsonProperty("products")]
710
public IEnumerable<ProductDto> Products { get; set; }
811
}
912
}

src/Umbraco.Cms.Integrations.Commerce.Shopify/Umbraco.Cms.Integrations.Commerce.Shopify.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@
264264
<Content Include="App_Plugins\UmbracoCms.Integrations\Commerce\Shopify\js\productPickerSettings.controller.js" />
265265
<Content Include="App_Plugins\UmbracoCms.Integrations\Commerce\Shopify\js\shopify.resource.js" />
266266
<Content Include="App_Plugins\UmbracoCms.Integrations\Commerce\Shopify\views\productPicker.html" />
267+
<Content Include="App_Plugins\UmbracoCms.Integrations\Commerce\Shopify\views\productPickerOverlay.html" />
267268
<Content Include="App_Plugins\UmbracoCms.Integrations\Commerce\Shopify\views\productPickerSettings.html" />
268269
</ItemGroup>
269270
<ItemGroup>

0 commit comments

Comments
 (0)