Skip to content

Commit 3c5e282

Browse files
committed
42083 V14: Integrations (Shopify)
- Moving project to a new folder
1 parent 684f0a5 commit 3c5e282

File tree

90 files changed

+668
-16
lines changed

Some content is hidden

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

90 files changed

+668
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@* @inherits Umbraco.Web.Mvc.UmbracoViewPage<List<Umbraco.Cms.Integrations.Commerce.Shopify.Models.ViewModels.ProductViewModel>>
2+
3+
@if (Model != null)
4+
{
5+
<dl class="products-list">
6+
@foreach (var product in Model)
7+
{
8+
<dt class="product-title">@product.Title</dt>
9+
<dd class="product-body">@Html.Raw(product.Body)</dd>
10+
@if (!string.IsNullOrEmpty(product.Image))
11+
{
12+
<img class="product-image" src="@product.Image" alt="@product.Title" />
13+
}
14+
}
15+
</dl>
16+
}
17+
18+
19+
*@
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@* @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<List<Umbraco.Cms.Integrations.Commerce.Shopify.Models.ViewModels.ProductViewModel>>
2+
3+
@if (Model != null)
4+
{
5+
<dl class="products-list">
6+
@foreach (var product in Model)
7+
{
8+
<dt class="product-title">@product.Title</dt>
9+
<dd class="product-body">@Html.Raw(product.Body)</dd>
10+
@if (!string.IsNullOrEmpty(product.Image))
11+
{
12+
<img class="product-image" src="@product.Image" alt="@product.Title" />
13+
}
14+
}
15+
</dl>
16+
} *@
Lines changed: 1 addition & 0 deletions
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.shopify-pagination .umb-pagination.pagination li:not(:first-child):not(:last-child) { display: none; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
function ProductPickerController($scope, editorService, notificationsService, umbracoCmsIntegrationsCommerceShopifyService, umbracoCmsIntegrationsCommerceShopifyResource) {
2+
3+
const oauthName = "OAuth";
4+
5+
var vm = this;
6+
7+
vm.loading = false;
8+
vm.selectedProducts = [];
9+
10+
vm.config = {
11+
validationLimit: {
12+
min: $scope.model.config.validationLimit.min ?? 0,
13+
max: $scope.model.config.validationLimit.max
14+
}
15+
}
16+
17+
// pagination
18+
vm.pagination = {
19+
pageNumber: 1,
20+
totalPages: 1,
21+
previousPageInfo: '',
22+
nextPageInfo: ''
23+
};
24+
vm.nextPage = nextPage;
25+
vm.prevPage = prevPage;
26+
vm.changePage = togglePage;
27+
vm.goToPage = togglePage;
28+
29+
// step 1. check configuration
30+
checkConfiguration(function () {
31+
// step 2.1 get total pages
32+
getTotalPages();
33+
// step 2.2 get products
34+
getProducts('');
35+
});
36+
37+
function getTotalPages() {
38+
umbracoCmsIntegrationsCommerceShopifyResource.getTotalPages().then(function (response) {
39+
vm.pagination.totalPages = response;
40+
});
41+
}
42+
43+
function getProducts(pageInfo) {
44+
vm.loading = true;
45+
46+
umbracoCmsIntegrationsCommerceShopifyResource.getProductsList(pageInfo).then(function (response) {
47+
if (response.isValid) {
48+
if (response.previousPageInfo) {
49+
vm.pagination.previousPageInfo = response.previousPageInfo;
50+
}
51+
if (response.nextPageInfo) {
52+
vm.pagination.nextPageInfo = response.nextPageInfo;
53+
}
54+
vm.productsList = response.result.products;
55+
56+
if ($scope.model.value != undefined && $scope.model.value.length > 0) {
57+
loadProductsPreview();
58+
};
59+
}
60+
vm.loading = false;
61+
});
62+
}
63+
64+
// products table events
65+
vm.selectProduct = function (item) {
66+
67+
var isProductSelected =
68+
$scope.model.selectedProducts.filter(function(i) { return i.id === item.id }).length > 0;
69+
70+
// check if products count is in the validation limit interval
71+
var isProductsCountValid = validateProductsCount(isProductSelected);
72+
if (isProductsCountValid) {
73+
if (isProductSelected) {
74+
$scope.model.selectedProducts =
75+
$scope.model.selectedProducts.filter(function(i) { return i.id !== item.id; });
76+
} else {
77+
$scope.model.selectedProducts.push(item);
78+
}
79+
}
80+
}
81+
82+
vm.isSelected = function (item, products) {
83+
return products.filter(function (i) { return i.id === item.id }).length > 0;
84+
}
85+
86+
vm.openProductsPickerOverlay = function () {
87+
var options = {
88+
title: "Shopify products",
89+
description: "Select product(s)",
90+
selectedProducts: vm.selectedProducts,
91+
config: vm.config,
92+
view: "/App_Plugins/UmbracoCms.Integrations/Commerce/Shopify/views/productPickerOverlay.html",
93+
size: "large",
94+
submit: function (selectedProducts) {
95+
vm.submit(selectedProducts);
96+
97+
loadProductsPreview();
98+
99+
editorService.close();
100+
},
101+
close: function () {
102+
editorService.close();
103+
}
104+
};
105+
106+
editorService.open(options);
107+
}
108+
109+
vm.submit = function (products) {
110+
$scope.model.value = products.map(function (item) { return item.id }).join(',');
111+
}
112+
113+
vm.remove = function (node) {
114+
vm.previewNodes = vm.previewNodes.filter(el => el.alias != node.alias);
115+
vm.selectedProducts = vm.selectedProducts.filter(el => el.id != node.alias);
116+
vm.submit(vm.previewNodes.length == 0 ? [] : vm.selectedProducts.filter(el => el.id != node.alias));
117+
}
118+
119+
function checkConfiguration(callback) {
120+
umbracoCmsIntegrationsCommerceShopifyResource.checkConfiguration().then(function (response) {
121+
122+
vm.status = {
123+
isValid: response.isValid === true,
124+
type: response.type,
125+
description: umbracoCmsIntegrationsCommerceShopifyService.configDescription[response.type.value],
126+
useOAuth: response.isValid === true && response.type.value === oauthName
127+
};
128+
129+
if (response.isValid === false) {
130+
vm.loading = false;
131+
vm.error = umbracoCmsIntegrationsCommerceShopifyService.configDescription.None;
132+
notificationsService.warning("Shopify API", umbracoCmsIntegrationsCommerceShopifyService.configDescription.None);
133+
} else {
134+
callback();
135+
}
136+
});
137+
}
138+
139+
function loadProductsPreview() {
140+
vm.previewNodes = [];
141+
142+
var ids = $scope.model.value.split(",");
143+
umbracoCmsIntegrationsCommerceShopifyResource.getProductsByIds(ids).then(function (response) {
144+
if (response.isValid) {
145+
response.result.products.forEach(el => {
146+
vm.selectedProducts.push(el);
147+
vm.previewNodes.push({
148+
icon: "icon-shopping-basket",
149+
name: el.title,
150+
alias: el.id
151+
});
152+
})
153+
}
154+
});
155+
}
156+
157+
function validateProductsCount(isRemoved) {
158+
159+
var updatedCount = isRemoved
160+
? $scope.model.selectedProducts.length - 1
161+
: $scope.model.selectedProducts.length + 1;
162+
163+
if (vm.config.validationLimit.min != null && vm.config.validationLimit.max != null) {
164+
return vm.config.validationLimit.min <= updatedCount && vm.config.validationLimit.max >= updatedCount;
165+
}
166+
167+
if (vm.config.validationLimit.min != null)
168+
return vm.config.validationLimit.min <= updatedCount;
169+
170+
if (vm.config.validationLimit.max != null)
171+
return vm.config.validationLimit.max >= updatedCount;
172+
}
173+
174+
// pagination events
175+
function nextPage(pageNumber) {
176+
getProducts(vm.pagination.nextPageInfo);
177+
}
178+
179+
function prevPage(pageNumber) {
180+
getProducts(vm.pagination.previousPageInfo);
181+
}
182+
183+
function togglePage(pageNumber) {
184+
if (pageNumber > vm.pagination.pageNumber) {
185+
// go to next
186+
getProducts(vm.pagination.nextPageInfo);
187+
vm.pagination.pageNumber = vm.pagination.pageNumber + 1;
188+
}
189+
else {
190+
// go to previous
191+
getProducts(vm.pagination.previousPageInfo);
192+
vm.pagination.pageNumber = vm.pagination.pageNumber - 1;
193+
}
194+
}
195+
}
196+
197+
angular.module("umbraco")
198+
.controller("Umbraco.Cms.Integrations.Commerce.Shopify.ProductPickerController", ProductPickerController);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
function productPickerSettingsController($scope, notificationsService, umbracoCmsIntegrationsCommerceShopifyService, umbracoCmsIntegrationsCommerceShopifyResource) {
2+
3+
var vm = this;
4+
5+
const oauthName = "OAuth";
6+
7+
vm.oauthSetup = {};
8+
vm.status = {};
9+
10+
umbracoCmsIntegrationsCommerceShopifyResource.checkConfiguration()
11+
.then(function (response) {
12+
13+
vm.status = {
14+
isValid: response.isValid === true,
15+
type: response.type,
16+
description: umbracoCmsIntegrationsCommerceShopifyService.configDescription[response.type.value],
17+
useOAuth: response.isValid === true && response.type.value === oauthName
18+
};
19+
20+
if (vm.status.useOAuth) {
21+
validateOAuthSetup();
22+
}
23+
24+
if (response.isValid !== true) {
25+
notificationsService.warning("Shopify Configuration",
26+
"Invalid setup. Please review the API/OAuth settings.");
27+
}
28+
});
29+
30+
vm.onConnectClick = function () {
31+
32+
umbracoCmsIntegrationsCommerceShopifyResource.getAuthorizationUrl().then(function (response) {
33+
vm.authWindow = window.open(response,
34+
"Authorize", "width=900,height=700,modal=yes,alwaysRaised=yes");
35+
36+
});
37+
}
38+
39+
vm.onRevokeToken = function () {
40+
umbracoCmsIntegrationsCommerceShopifyResource.revokeAccessToken().then(function (response) {
41+
vm.oauthSetup.isConnected = false;
42+
notificationsService.success("Shopify Configuration", "OAuth connection revoked.");
43+
});
44+
}
45+
46+
// authorization listener
47+
window.addEventListener("message", function (event) {
48+
if (event.data.type === "shopify:oauth:success") {
49+
umbracoCmsIntegrationsCommerceShopifyResource.getAccessToken(event.data.code).then(function (response) {
50+
if (response.startsWith("Error:")) {
51+
notificationsService.error("Shopify Configuration", response);
52+
} else {
53+
vm.oauthSetup.isConnected = true;
54+
vm.status.description = umbracoCmsIntegrationsCommerceShopifyService.configDescription.OAuthConnected;
55+
notificationsService.success("Shopify Configuration", "OAuth connected.");
56+
}
57+
});
58+
59+
}
60+
}, false);
61+
62+
63+
function validateOAuthSetup() {
64+
umbracoCmsIntegrationsCommerceShopifyResource.validateAccessToken().then(function (response) {
65+
66+
vm.oauthSetup = {
67+
isConnected: response.isValid,
68+
isAccessTokenExpired: response.isExpired,
69+
isAccessTokenValid: response.isValid
70+
}
71+
72+
if (vm.oauthSetup.isConnected === true && vm.oauthSetup.isAccessTokenValid === true) {
73+
vm.status.description = umbracoCmsIntegrationsCommerceShopifyService.configDescription.OAuthConnected;
74+
}
75+
76+
// refresh access token
77+
if (vm.oauthSetup.isAccessTokenExpired === true) {
78+
umbracoCmsIntegrationsCommerceShopifyService.refreshAccessToken().then(function (response) {});
79+
}
80+
81+
});
82+
}
83+
}
84+
85+
angular.module("umbraco")
86+
.controller("Umbraco.Cms.Integrations.Commerce.Shopify.ProductPickerSettingsController", productPickerSettingsController);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
angular.module("umbraco.resources")
2+
.factory("umbracoCmsIntegrationsCommerceShopifyResource",
3+
function($http, umbRequestHelper) {
4+
const apiEndpoint = "backoffice/UmbracoCmsIntegrationsCommerceShopify/Products";
5+
6+
return {
7+
checkConfiguration: function () {
8+
return umbRequestHelper.resourcePromise(
9+
$http.get(`${apiEndpoint}/CheckConfiguration`),
10+
"Failed to get resource");
11+
},
12+
getAuthorizationUrl: function () {
13+
return umbRequestHelper.resourcePromise(
14+
$http.get(`${apiEndpoint}/GetAuthorizationUrl`),
15+
"Failed");
16+
},
17+
getAccessToken: function (authorizationCode) {
18+
return umbRequestHelper.resourcePromise(
19+
$http.post(`${apiEndpoint}/GetAccessToken`, { code: authorizationCode }),
20+
"Failed");
21+
},
22+
revokeAccessToken: function () {
23+
return umbRequestHelper.resourcePromise(
24+
$http.post(`${apiEndpoint}/RevokeAccessToken`),
25+
"Failed");
26+
},
27+
validateAccessToken: function () {
28+
return umbRequestHelper.resourcePromise(
29+
$http.get(`${apiEndpoint}/ValidateAccessToken`),
30+
"Failed");
31+
},
32+
getProductsList: function(pageInfo) {
33+
return umbRequestHelper.resourcePromise(
34+
$http.get(`${apiEndpoint}/GetList?pageInfo=${pageInfo}`), "Failed to get resource");
35+
},
36+
getProductsByIds: function (ids) {
37+
return umbRequestHelper.resourcePromise(
38+
$http.post(`${apiEndpoint}/GetListByIds`, { ids: ids }), "Failed to get resource");
39+
},
40+
getTotalPages: function () {
41+
return umbRequestHelper.resourcePromise(
42+
$http.get(`${apiEndpoint}/GetTotalPages`), "Failed to get resource");
43+
}
44+
};
45+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function shopifyService() {
2+
return {
3+
configDescription: {
4+
API: "An access token is configured and will be used to connect to your Shopify account.",
5+
OAuth:
6+
"No access token is configured. To connect to your Shopify account using OAuth click 'Connect', select your account and agree to the permissions.",
7+
None: "No access token or OAuth configuration could be found. Please review your settings before continuing.",
8+
OAuthConnected:
9+
"OAuth is configured and an access token is available to connect to your Shopify account. To revoke, click 'Revoke'"
10+
}
11+
}
12+
}
13+
14+
angular.module("umbraco.services")
15+
.service("umbracoCmsIntegrationsCommerceShopifyService", shopifyService);

0 commit comments

Comments
 (0)