diff --git a/pages/api/search-products.ts b/pages/api/search-products.ts index f0206b722..529e1b5f7 100644 --- a/pages/api/search-products.ts +++ b/pages/api/search-products.ts @@ -1,10 +1,7 @@ import { NextApiRequest, NextApiResponse } from "next" -import { getConfig } from '@framework/api' -import getSiteInfo from '@framework/api/operations/get-site-info' -import getAllProducts from '@framework/api/operations/get-all-products' - +import commerce from '@lib/api/commerce' export default async (req: NextApiRequest, res: NextApiResponse) => { @@ -24,25 +21,41 @@ export default async (req: NextApiRequest, res: NextApiResponse) => { } try { - const filter = req.query.filter ?? "" + const filter = `${req.query.search}`.toLowerCase() // const products = await getProducts({filter}) - const locale = "en-US" + + + const locale = "en-us" const preview = false - - const config = getConfig({ locale }) - - - // Get Best Newest Products - const { products } = await getAllProducts({ - variables: { field: 'newestProducts', first: 12 }, + const config = { locale, locales: [locale] } + const { products } = await commerce.getAllProducts({ + variables: { first: 1000 }, config, preview, }) + + const ret = products + .filter(p => { + return filter === "" + || p.name.toLowerCase().indexOf(filter) !== -1 + || p.description.toLowerCase().indexOf(filter) !== -1 + }) + .map(p => { + + return { + name: p.name, + imageUrl: p.images[0].url, + price: p.price, + id: p.id, + description: p.description + } + }) + res.statusCode = 200 - res.json(products) + res.json(ret) } catch (e) { diff --git a/public/custom-fields.js b/public/custom-fields.js new file mode 100644 index 000000000..e3cf2b647 --- /dev/null +++ b/public/custom-fields.js @@ -0,0 +1,378 @@ +/* eslint-disable new-parens */ +/* eslint-disable eqeqeq */ +/* eslint-disable no-undef */ + +/** + * THIS FILE IS USED FOR THE AGILITY'S CUSTOM FIELDS + */ + +var baseUrl = "https://agility-nextjs-cloudinary.vercel.app/" + + +var FriendlyURLFormField = function () { + var self = this; + + self.Label = "Friendly URL"; + self.ReferenceName = "FriendlyURL"; + + self.Render = function (options) { + /// + /// The Render handler for this field. Create any elements and bindings that you might need, pull down resources. + /// + /// The options used to render this field. + } + + /// The partial HTML template that represents your custom field. Your ViewModel will be automatically bound to this template. + self.Template = 'https://agility.github.io/CustomFields/friendly-url/html/friendly-url-template.html'; + + /// type="Array">The Javscript dependencies that must be loaded before your ViewModel is bound. They will be loaded in the order you specify. + self.DependenciesJS = []; + + /// The CSS dependencies that must be loaded before your ViewModel is bound. They will be loaded in the order you specify. + self.DependenciesCSS = []; + + + /// The KO ViewModel that will be binded to your HTML template + self.ViewModel = function (options) { + /// The KO ViewModel that will be binded to your HTML template. + /// + /// The .field-row jQuery Dom Element. + /// The entire Content Item object including Values and their KO Observable properties of all other fields on the form. + /// The value binding of thie Custom Field Type. Get and set this field's value by using this property. + /// Object representing the field's settings such as 'Hidden', 'Label', and 'Description' + /// Represents if this field should be readonly or not. + /// + + var self = this; + self.relatedField = "Title"; //the other field value we want to make friendly + self.value = options.fieldBinding; + self.contentID = options.contentItem.ContentID; + self.attrBinding = {}; + + if (options.fieldSetting.Settings.Required === "True") { + self.attrBinding['data-parsley-required'] = true; + } + + + self.makeFriendlyString = function (s) { + if (s) { + var r = s.toLowerCase(); + r = r.replace(new RegExp("\\s", 'g'), "-"); + r = r.replace(new RegExp("[àáâãäå]", 'g'), "a"); + r = r.replace(new RegExp("æ", 'g'), "ae"); + r = r.replace(new RegExp("ç", 'g'), "c"); + r = r.replace(new RegExp("[èéêë]", 'g'), "e"); + r = r.replace(new RegExp("[ìíîï]", 'g'), "i"); + r = r.replace(new RegExp("ñ", 'g'), "n"); + r = r.replace(new RegExp("[òóôõö]", 'g'), "o"); + r = r.replace(new RegExp("œ", 'g'), "oe"); + r = r.replace(new RegExp("[ùúûü]", 'g'), "u"); + r = r.replace(new RegExp("[ýÿ]", 'g'), "y"); + + r = r.replace(new RegExp("[^\\w\\-@-]", 'g'), "-"); + r = r.replace(new RegExp("--+", 'g'), "-"); + + + if (r.lastIndexOf("-") > 0 && r.lastIndexOf("-") == r.length - 1) { + r = r.substring(0, r.length - 1); + } + } + + return r; + }; + + self.regenerateUrl = function () { + ContentManager.ViewModels.Navigation.messages().show("By changing the URL you could create broken links.\nWe recommend you add in a URL redirection from the old URL to the new URL.\nAre you sure you wish to continue?", "Re-generate URL", + ContentManager.Global.MessageType.Question, [{ + name: "OK", + defaultAction: true, + callback: function () { + var friendlyStr = self.makeFriendlyString(options.contentItem.Values[self.relatedField]()); + self.value(friendlyStr); + } + }, + { + name: "Cancel", + cancelAction: true, + callback: function () { + //do nothing... + } + }]); + } + + //subscribe to the related field changes + options.contentItem.Values[self.relatedField].subscribe(function (newVal) { + //auto generate if this is a new item + if (options.contentItem.ContentID() < 0) { + var friendlyStr = self.makeFriendlyString(newVal); + self.value(friendlyStr); + } + + }); + + } +} + +ContentManager.Global.CustomInputFormFields.push(new FriendlyURLFormField()); + +// +// Markdown field +// +var MarkdownCustomField = function () { + /// The type definition of this Agility Custom Field Type. + var self = this; + + /// The display name of the Custom Field Type + self.Label = "Markdown"; + + /// The internal reference name of the Custom Field Type. Must not contain any special characters. + self.ReferenceName = "Markdown"; + + /// This function runs every time the field is rendered + self.Render = function (options) { + /// + /// The Render handler for this field. Create any elements and bindings that you might need, pull down resources. + /// This method will be called everytime to the field value changes. + /// + /// The options used to render this field. + + + + //get our base element + var $pnl = $(".markdown-field", options.$elem); + + if ($pnl.size() == 0) { + /* + Pull in the simple but awesome MD editor here: + https://github.com/sparksuite/simplemde-markdown-editor + */ + var htmlContent = ` +
+ + + +
+ `; + //pull down the html template and load it into the element + options.$elem.append(htmlContent) + + $pnl = $(".markdown-field", options.$elem); + + //bind our viewmodel to this + var viewModel = function () { + + /// The KO ViewModel that will be binded to your HTML template. + /// + /// The .field-row jQuery Dom Element. + /// The entire Content Item object including Values and their KO Observable properties of all other fields on the form. + /// The value binding of thie Custom Field Type. Get and set this field's value by using this property. + /// Object representing the field's settings such as 'Hidden', 'Label', and 'Description' + /// Represents if this field should be readonly or not. + /// + var self = this; + + self.value = options.fieldBinding; //.extend({ throttle: 500 }); + + //TODO: determine a better way to detect if the SimpleMDE object is ready + setTimeout(function () { + + var simplemde = new SimpleMDE({ element: $("textarea", options.$elem)[0] }); + simplemde.codemirror.on("change", function () { + self.value(simplemde.value()) + }); + + }, 1000) + + } + + ko.applyBindings(viewModel, $pnl.get(0)); + } + + } +} + +ContentManager.Global.CustomInputFormFields.push(new MarkdownCustomField()); + +var ChooseProductCustomField = function () { + /// The type definition of this Agility Custom Field Type. + var self = this; + + /// The display name of the Custom Field Type + self.Label = "Choose Ecommerce Product"; + + /// The internal reference name of the Custom Field Type. Must not contain any special characters. + self.ReferenceName = "ChooseEcommerceProduct"; + + /// This function runs every time the field is rendered + self.Render = function (options) { + /// + /// The Render handler for this field. Create any elements and bindings that you might need, pull down resources. + /// This method will be called everytime to the field value changes. + /// + /// The options used to render this field. + + + + //get our base element + var $pnl = $(".product-picker-field", options.$elem); + + if ($pnl.size() == 0) { + + var htmlContent = ` + + `; + //pull down the html template and load it into the element + options.$elem.append(htmlContent) + + $pnl = $(".product-picker-field", options.$elem); + + + //bind our viewmodel to this + var viewModel = function () { + + /// The KO ViewModel that will be binded to your HTML template. + /// + /// The .field-row jQuery Dom Element. + /// The entire Content Item object including Values and their KO Observable properties of all other fields on the form. + /// The value binding of thie Custom Field Type. Get and set this field's value by using this property. + /// Object representing the field's settings such as 'Hidden', 'Label', and 'Description' + /// Represents if this field should be readonly or not. + /// + var self = this; + + self.ajaxRequest = null; + + self.selectedValue = options.fieldBinding.extend({ throttle: 500 }); + + self.formatResult = function (item) { + + return $(`
${item.node.title}
`); + //return item.node.title; + }; + + + + self.formatSelection = function (item) { + + return $(`
${item.node.title}
`); + + }; + self.ajaxRequest = null; + + self.select2 = { + label: 'Product', + readOnly: false, + value: options.fieldBinding, + multiple: false, + maximumSelectionSize: 1, + minimumInputLength: 0, + placeholder: 'Find product...', + formatResult: self.formatResult, + formatSelection: self.formatSelection, + templateResult: self.templateResult, + + matcher: function (term, text) { + return true; + }, + + id: function (obj) { + //set content of the Agility CMS Content Item + + //options.contentItem.Values.ExternalID(obj.ID) + + //options.contentItem.Values.MyField1(obj.Value1) + //options.contentItem.Values.MyField2(obj.Value2) + //etc... + + //save the whole thing as JSON + return JSON.stringify(obj.node) + }, + + ajax: { // instead of writing the function to execute the request we use Select2's convenient helper + //url: "https://sample-swag-shopify.vercel.app/api/search-products", + url: "http://localhost:3000/api/search-products", + dataType: 'json', + type: "get", + quietMillis: 250, + + originalValue: ko.unwrap(options.fieldBinding), + term: "", + data: function (term, page, params) { + return { + search: term, // search term + }; + }, + results: function (data, page) { + + return { + results: data + }; + }, + current: function (data) { + + }, + cache: true + }, + initSelection: function (element, callback) { + //use the hidden "product name" field + var json = ko.unwrap(options.fieldBinding); + console.log({json}) + if (json && json.length > 0) { + + var node = JSON.parse(json) + console.log({node}) + callback({node}) + } + + + + // console.log(val) + + // var label = ko.unwrap(options.contentItem.Values.ProductName); + + // if (val && label) { + // var data = { + // node: { + // id: val, + // title: label + // } + // }; + + // callback(data); + // } + }, + allowClear: false, + dropdownCssClass: "bigdrop" + }; + } + + ko.applyBindings(viewModel, $pnl.get(0)); + } + + } +} + +ContentManager.Global.CustomInputFormFields.push(new ChooseProductCustomField());