├── .DS_Store ├── .gitattributes ├── LICENSE ├── README.md ├── config ├── admin.js ├── server.js └── store.js ├── docs ├── README.md ├── developer.md ├── getting-started.md ├── initialize-mongodb.md └── structure.md ├── locales ├── admin │ ├── en.json │ ├── ru.json │ ├── uk.json │ └── zh_CN.json └── store │ ├── en.json │ ├── ru.json │ ├── uk.json │ └── zh_CN.json ├── logs └── README.md ├── package.json ├── process.json ├── public ├── admin-assets │ ├── css │ │ ├── flexboxgrid.min.css │ │ └── style.css │ ├── data │ │ ├── countries.js │ │ ├── currencies.js │ │ └── timezones.js │ ├── images │ │ ├── apps │ │ │ ├── facebook-customer-chat-plugin.png │ │ │ ├── facebook.png │ │ │ ├── google_analytics.png │ │ │ ├── jivosite.png │ │ │ ├── messenger.png │ │ │ └── site_verification.png │ │ └── shortcut.png │ ├── manifest.json │ └── tinymce │ │ ├── langs │ │ ├── ar.js │ │ ├── az.js │ │ ├── be.js │ │ ├── bg_BG.js │ │ ├── bs.js │ │ ├── ca.js │ │ ├── cs.js │ │ ├── cs_CZ.js │ │ ├── cy.js │ │ ├── da.js │ │ ├── de.js │ │ ├── de_AT.js │ │ ├── el.js │ │ ├── en_CA.js │ │ ├── en_GB.js │ │ ├── eo.js │ │ ├── es.js │ │ ├── es_MX.js │ │ ├── et.js │ │ ├── eu.js │ │ ├── fa.js │ │ ├── fa_IR.js │ │ ├── fi.js │ │ ├── fo.js │ │ ├── fr_CH.js │ │ ├── fr_FR.js │ │ ├── ga.js │ │ ├── gd.js │ │ ├── gl.js │ │ ├── he_IL.js │ │ ├── hi_IN.js │ │ ├── hr.js │ │ ├── hu_HU.js │ │ ├── hy.js │ │ ├── id.js │ │ ├── is_IS.js │ │ ├── it.js │ │ ├── ja.js │ │ ├── ka_GE.js │ │ ├── kab.js │ │ ├── km_KH.js │ │ ├── ko_KR.js │ │ ├── ku.js │ │ ├── ku_IQ.js │ │ ├── lb.js │ │ ├── lt.js │ │ ├── lv.js │ │ ├── mk_MK.js │ │ ├── ml_IN.js │ │ ├── nb_NO.js │ │ ├── nl.js │ │ ├── oc.js │ │ ├── pl.js │ │ ├── pt_BR.js │ │ ├── pt_PT.js │ │ ├── readme.md │ │ ├── ro.js │ │ ├── ru.js │ │ ├── sk.js │ │ ├── sl_SI.js │ │ ├── sv_SE.js │ │ ├── ta.js │ │ ├── ta_IN.js │ │ ├── tg.js │ │ ├── th_TH.js │ │ ├── tr.js │ │ ├── tr_TR.js │ │ ├── tt.js │ │ ├── ug.js │ │ ├── uk.js │ │ ├── uk_UA.js │ │ ├── vi.js │ │ ├── vi_VN.js │ │ ├── zh_CN.GB2312.js │ │ ├── zh_CN.js │ │ └── zh_TW.js │ │ ├── license.txt │ │ ├── plugins │ │ ├── advlist │ │ │ └── plugin.min.js │ │ ├── anchor │ │ │ └── plugin.min.js │ │ ├── autolink │ │ │ └── plugin.min.js │ │ ├── autoresize │ │ │ └── plugin.min.js │ │ ├── autosave │ │ │ └── plugin.min.js │ │ ├── bbcode │ │ │ └── plugin.min.js │ │ ├── charmap │ │ │ └── plugin.min.js │ │ ├── code │ │ │ └── plugin.min.js │ │ ├── codesample │ │ │ ├── css │ │ │ │ └── prism.css │ │ │ └── plugin.min.js │ │ ├── colorpicker │ │ │ └── plugin.min.js │ │ ├── contextmenu │ │ │ └── plugin.min.js │ │ ├── directionality │ │ │ └── plugin.min.js │ │ ├── emoticons │ │ │ ├── img │ │ │ │ ├── smiley-cool.gif │ │ │ │ ├── smiley-cry.gif │ │ │ │ ├── smiley-embarassed.gif │ │ │ │ ├── smiley-foot-in-mouth.gif │ │ │ │ ├── smiley-frown.gif │ │ │ │ ├── smiley-innocent.gif │ │ │ │ ├── smiley-kiss.gif │ │ │ │ ├── smiley-laughing.gif │ │ │ │ ├── smiley-money-mouth.gif │ │ │ │ ├── smiley-sealed.gif │ │ │ │ ├── smiley-smile.gif │ │ │ │ ├── smiley-surprised.gif │ │ │ │ ├── smiley-tongue-out.gif │ │ │ │ ├── smiley-undecided.gif │ │ │ │ ├── smiley-wink.gif │ │ │ │ └── smiley-yell.gif │ │ │ └── plugin.min.js │ │ ├── example │ │ │ ├── dialog.html │ │ │ └── plugin.min.js │ │ ├── example_dependency │ │ │ └── plugin.min.js │ │ ├── fullpage │ │ │ └── plugin.min.js │ │ ├── fullscreen │ │ │ └── plugin.min.js │ │ ├── hr │ │ │ └── plugin.min.js │ │ ├── image │ │ │ └── plugin.min.js │ │ ├── imagetools │ │ │ └── plugin.min.js │ │ ├── importcss │ │ │ └── plugin.min.js │ │ ├── insertdatetime │ │ │ └── plugin.min.js │ │ ├── layer │ │ │ └── plugin.min.js │ │ ├── legacyoutput │ │ │ └── plugin.min.js │ │ ├── link │ │ │ └── plugin.min.js │ │ ├── lists │ │ │ └── plugin.min.js │ │ ├── media │ │ │ ├── moxieplayer.swf │ │ │ └── plugin.min.js │ │ ├── nonbreaking │ │ │ └── plugin.min.js │ │ ├── noneditable │ │ │ └── plugin.min.js │ │ ├── pagebreak │ │ │ └── plugin.min.js │ │ ├── paste │ │ │ └── plugin.min.js │ │ ├── preview │ │ │ └── plugin.min.js │ │ ├── print │ │ │ └── plugin.min.js │ │ ├── save │ │ │ └── plugin.min.js │ │ ├── searchreplace │ │ │ └── plugin.min.js │ │ ├── spellchecker │ │ │ └── plugin.min.js │ │ ├── tabfocus │ │ │ └── plugin.min.js │ │ ├── table │ │ │ └── plugin.min.js │ │ ├── template │ │ │ └── plugin.min.js │ │ ├── textcolor │ │ │ └── plugin.min.js │ │ ├── textpattern │ │ │ └── plugin.min.js │ │ ├── visualblocks │ │ │ ├── css │ │ │ │ └── visualblocks.css │ │ │ └── plugin.min.js │ │ ├── visualchars │ │ │ └── plugin.min.js │ │ └── wordcount │ │ │ └── plugin.min.js │ │ ├── skins │ │ └── lightgray │ │ │ ├── content.inline.min.css │ │ │ ├── content.min.css │ │ │ ├── fonts │ │ │ ├── tinymce-small.eot │ │ │ ├── tinymce-small.svg │ │ │ ├── tinymce-small.ttf │ │ │ ├── tinymce-small.woff │ │ │ ├── tinymce.eot │ │ │ ├── tinymce.svg │ │ │ ├── tinymce.ttf │ │ │ └── tinymce.woff │ │ │ ├── img │ │ │ ├── anchor.gif │ │ │ ├── loader.gif │ │ │ ├── object.gif │ │ │ └── trans.gif │ │ │ ├── skin.ie7.min.css │ │ │ └── skin.min.css │ │ ├── themes │ │ ├── inlite │ │ │ └── theme.min.js │ │ └── modern │ │ │ └── theme.min.js │ │ └── tinymce.min.js ├── content │ └── README.md ├── robots.template ├── sw-toolbox.js └── sw.js ├── scripts ├── theme-export.sh └── theme-install.sh ├── src ├── admin │ └── client │ │ ├── app.js │ │ ├── apps │ │ ├── facebook-customer-chat.js │ │ ├── facebook-sdk.js │ │ ├── google-analytics.js │ │ ├── index.js │ │ ├── jivosite.js │ │ └── site-verification.js │ │ ├── index.html │ │ ├── index.js │ │ ├── lib │ │ ├── api.js │ │ ├── auth.js │ │ ├── data.js │ │ ├── events.js │ │ ├── helper.js │ │ ├── settings.js │ │ ├── text.js │ │ └── webstoreAuth.js │ │ ├── modules │ │ ├── apps │ │ │ ├── account │ │ │ │ ├── components │ │ │ │ │ ├── account.js │ │ │ │ │ ├── details.js │ │ │ │ │ ├── developer.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── appDetails │ │ │ │ ├── description.js │ │ │ │ ├── index.js │ │ │ │ └── style.css │ │ │ ├── head │ │ │ │ ├── components │ │ │ │ │ └── buttons.js │ │ │ │ └── index.js │ │ │ ├── reducer.js │ │ │ ├── serviceDetails │ │ │ │ ├── components │ │ │ │ │ ├── actions.js │ │ │ │ │ ├── description.js │ │ │ │ │ ├── details.js │ │ │ │ │ ├── logs.js │ │ │ │ │ ├── settings.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ └── services │ │ │ │ ├── components │ │ │ │ ├── appItem.js │ │ │ │ ├── item.js │ │ │ │ ├── list.js │ │ │ │ ├── serviceItem.js │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ ├── customerGroups │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── components │ │ │ │ └── list.js │ │ │ ├── edit │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── head │ │ │ │ ├── components │ │ │ │ │ └── buttons.js │ │ │ │ └── index.js │ │ │ ├── list │ │ │ │ └── index.js │ │ │ ├── reducer.js │ │ │ └── select │ │ │ │ └── index.js │ │ ├── customers │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── edit │ │ │ │ ├── components │ │ │ │ │ ├── addressForm.js │ │ │ │ │ ├── addresses.js │ │ │ │ │ ├── details.js │ │ │ │ │ ├── orders.js │ │ │ │ │ ├── style.css │ │ │ │ │ ├── summary.js │ │ │ │ │ └── summaryForm.js │ │ │ │ └── index.js │ │ │ ├── filter │ │ │ │ ├── components │ │ │ │ │ ├── fields.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── list │ │ │ │ ├── components │ │ │ │ │ ├── head.js │ │ │ │ │ ├── item.js │ │ │ │ │ ├── list.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── listHead │ │ │ │ ├── components │ │ │ │ │ ├── buttons.js │ │ │ │ │ └── search.js │ │ │ │ └── index.js │ │ │ └── reducer.js │ │ ├── files │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── list │ │ │ │ ├── components │ │ │ │ │ ├── fileUploader │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── style.css │ │ │ │ │ ├── form.js │ │ │ │ │ ├── headButtons.js │ │ │ │ │ └── style.css │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ │ └── reducer.js │ │ ├── head │ │ │ ├── components │ │ │ │ ├── appBar.js │ │ │ │ └── drawer.js │ │ │ └── index.js │ │ ├── orderStatuses │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── components │ │ │ │ └── list.js │ │ │ ├── edit │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── head │ │ │ │ ├── components │ │ │ │ │ └── buttons.js │ │ │ │ └── index.js │ │ │ ├── list │ │ │ │ └── index.js │ │ │ ├── reducer.js │ │ │ └── select │ │ │ │ └── index.js │ │ ├── orders │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── edit │ │ │ │ ├── components │ │ │ │ │ ├── customer.js │ │ │ │ │ ├── details.js │ │ │ │ │ ├── items.js │ │ │ │ │ ├── shippingAddressForm.js │ │ │ │ │ ├── style.css │ │ │ │ │ ├── summary.js │ │ │ │ │ ├── summaryForm.js │ │ │ │ │ └── totals.js │ │ │ │ └── index.js │ │ │ ├── editHead │ │ │ │ ├── components │ │ │ │ │ └── buttons.js │ │ │ │ └── index.js │ │ │ ├── list │ │ │ │ ├── components │ │ │ │ │ ├── head.js │ │ │ │ │ ├── item.js │ │ │ │ │ ├── list.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── listFilter │ │ │ │ ├── components │ │ │ │ │ ├── fields.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── listHead │ │ │ │ ├── components │ │ │ │ │ ├── buttons.js │ │ │ │ │ └── search.js │ │ │ │ └── index.js │ │ │ └── reducer.js │ │ ├── pages │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── edit │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ ├── headButtons.js │ │ │ │ │ └── style.css │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ │ ├── list │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── headButtons.js │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ │ └── reducer.js │ │ ├── productCategories │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── components │ │ │ │ └── list.js │ │ │ ├── edit │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── head │ │ │ │ ├── components │ │ │ │ │ └── buttons.js │ │ │ │ └── index.js │ │ │ ├── list │ │ │ │ └── index.js │ │ │ ├── reducer.js │ │ │ └── select │ │ │ │ └── index.js │ │ ├── products │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── edit │ │ │ │ ├── additional │ │ │ │ │ ├── components │ │ │ │ │ │ ├── form.js │ │ │ │ │ │ └── style.css │ │ │ │ │ └── index.js │ │ │ │ ├── attributes │ │ │ │ │ ├── components │ │ │ │ │ │ ├── form.js │ │ │ │ │ │ └── style.css │ │ │ │ │ └── index.js │ │ │ │ ├── general │ │ │ │ │ ├── components │ │ │ │ │ │ ├── form.js │ │ │ │ │ │ └── style.css │ │ │ │ │ └── index.js │ │ │ │ ├── images │ │ │ │ │ ├── components │ │ │ │ │ │ └── images.js │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ ├── inventory │ │ │ │ │ ├── components │ │ │ │ │ │ ├── form.js │ │ │ │ │ │ └── style.css │ │ │ │ │ └── index.js │ │ │ │ ├── option │ │ │ │ │ ├── components │ │ │ │ │ │ ├── option.js │ │ │ │ │ │ ├── style.css │ │ │ │ │ │ └── values.js │ │ │ │ │ └── index.js │ │ │ │ └── variants │ │ │ │ │ ├── components │ │ │ │ │ ├── grid.js │ │ │ │ │ └── style.css │ │ │ │ │ └── index.js │ │ │ ├── editHead │ │ │ │ ├── components │ │ │ │ │ └── buttons.js │ │ │ │ └── index.js │ │ │ ├── list │ │ │ │ ├── components │ │ │ │ │ ├── head.js │ │ │ │ │ ├── item.js │ │ │ │ │ ├── list.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── listFilter │ │ │ │ ├── components │ │ │ │ │ ├── filter.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── listHead │ │ │ │ ├── components │ │ │ │ │ ├── buttons.js │ │ │ │ │ └── search.js │ │ │ │ └── index.js │ │ │ └── reducer.js │ │ ├── settings │ │ │ ├── actionTypes.js │ │ │ ├── actions.js │ │ │ ├── checkout │ │ │ │ ├── components │ │ │ │ │ └── form.js │ │ │ │ └── index.js │ │ │ ├── checkoutFields │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── email │ │ │ │ ├── components │ │ │ │ │ └── form.js │ │ │ │ └── index.js │ │ │ ├── emailTemplates │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── general │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── generalLogo │ │ │ │ ├── components │ │ │ │ │ └── form.js │ │ │ │ └── index.js │ │ │ ├── paymentGateway │ │ │ │ ├── availablePaymentGateways.js │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ ├── gatewaySettings.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── payments │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── headButtons.js │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ │ ├── paymentsEdit │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ ├── headButtons.js │ │ │ │ │ ├── selectShipping.js │ │ │ │ │ └── style.css │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ │ ├── reducer.js │ │ │ ├── shipping │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── headButtons.js │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ │ ├── shippingEdit │ │ │ │ ├── components │ │ │ │ │ ├── fieldsEditor.js │ │ │ │ │ ├── form.js │ │ │ │ │ ├── headButtons.js │ │ │ │ │ └── style.css │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ │ ├── smtp │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── theme │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ ├── themeSettings │ │ │ │ ├── components │ │ │ │ │ ├── arrayEditor.js │ │ │ │ │ ├── dynamicEditControl.js │ │ │ │ │ ├── form.js │ │ │ │ │ ├── imageEditor.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ └── tokens │ │ │ │ ├── edit │ │ │ │ ├── components │ │ │ │ │ ├── form.js │ │ │ │ │ ├── selectScopes.js │ │ │ │ │ └── style.css │ │ │ │ └── index.js │ │ │ │ └── list │ │ │ │ ├── components │ │ │ │ ├── form.js │ │ │ │ └── headButtons.js │ │ │ │ ├── head.js │ │ │ │ └── index.js │ │ └── shared │ │ │ ├── confirmation │ │ │ └── index.js │ │ │ ├── editor │ │ │ └── index.js │ │ │ ├── form │ │ │ └── index.js │ │ │ ├── imageUpload │ │ │ ├── index.js │ │ │ └── style.css │ │ │ ├── imageUploadMultiple │ │ │ ├── index.js │ │ │ ├── item.js │ │ │ ├── style.css │ │ │ └── uploader.js │ │ │ ├── productSearch │ │ │ └── index.js │ │ │ └── tinymce │ │ │ ├── components │ │ │ └── TinyMCE.js │ │ │ ├── helpers │ │ │ ├── ucFirst.js │ │ │ └── uuid.js │ │ │ └── index.js │ │ ├── rootReducer.js │ │ └── routes │ │ ├── apps │ │ ├── index.js │ │ └── login.js │ │ ├── customers │ │ ├── edit.js │ │ ├── groups │ │ │ └── index.js │ │ └── index.js │ │ ├── files.js │ │ ├── home.js │ │ ├── login.js │ │ ├── logout.js │ │ ├── notFound.js │ │ ├── orders │ │ ├── edit.js │ │ ├── index.js │ │ └── statuses │ │ │ └── index.js │ │ ├── pages │ │ ├── edit.js │ │ └── index.js │ │ ├── products │ │ ├── categories │ │ │ └── index.js │ │ ├── edit.js │ │ └── index.js │ │ └── settings.js ├── api │ └── server │ │ ├── ajax.js │ │ ├── ajaxRouter.js │ │ ├── apiRouter.js │ │ ├── controllers │ │ ├── apps.js │ │ ├── customerGroups.js │ │ ├── customers.js │ │ ├── data.js │ │ ├── files.js │ │ ├── notifications.js │ │ ├── orderStatuses.js │ │ ├── orders.js │ │ ├── pages.js │ │ ├── paymentGateways.js │ │ ├── paymentMethods.js │ │ ├── productCategories.js │ │ ├── products.js │ │ ├── redirects.js │ │ ├── settings.js │ │ ├── shippingMethods.js │ │ ├── sitemap.js │ │ ├── theme.js │ │ └── tokens.js │ │ ├── index.js │ │ ├── lib │ │ ├── email.js │ │ ├── events.js │ │ ├── mongo.js │ │ ├── parse.js │ │ ├── security.js │ │ ├── settings.js │ │ └── utils.js │ │ ├── paymentGateways │ │ ├── LiqPay.js │ │ ├── PayPalCheckout.js │ │ └── index.js │ │ ├── routes.js │ │ ├── routes │ │ ├── apps.js │ │ ├── customerGroups.js │ │ ├── customers.js │ │ ├── files.js │ │ ├── notifications.js │ │ ├── orderStatuses.js │ │ ├── orders.js │ │ ├── pages.js │ │ ├── paymentGateways.js │ │ ├── paymentMethods.js │ │ ├── productCategories.js │ │ ├── products.js │ │ ├── redirects.js │ │ ├── settings.js │ │ ├── shippingMethods.js │ │ ├── sitemap.js │ │ ├── theme.js │ │ └── tokens.js │ │ └── services │ │ ├── apps │ │ └── settings.js │ │ ├── customers │ │ ├── customerGroups.js │ │ └── customers.js │ │ ├── data.js │ │ ├── files.js │ │ ├── orders │ │ ├── orderAddress.js │ │ ├── orderDiscounts.js │ │ ├── orderItems.js │ │ ├── orderStatuses.js │ │ ├── orderTransactions.js │ │ ├── orders.js │ │ ├── paymentMethods.js │ │ ├── paymentMethodsLight.js │ │ ├── shippingMethods.js │ │ └── shippingMethodsLight.js │ │ ├── pages │ │ └── pages.js │ │ ├── products │ │ ├── images.js │ │ ├── optionValues.js │ │ ├── options.js │ │ ├── productCategories.js │ │ ├── products.js │ │ ├── stock.js │ │ └── variants.js │ │ ├── redirects.js │ │ ├── security │ │ └── tokens.js │ │ ├── settings │ │ ├── checkoutFields.js │ │ ├── email.js │ │ ├── emailTemplates.js │ │ ├── paymentGateways.js │ │ └── settings.js │ │ ├── sitemap.js │ │ └── theme │ │ ├── assets.js │ │ ├── placeholders.js │ │ ├── settings.js │ │ └── theme.js ├── index.js └── store │ ├── client │ ├── api.js │ ├── index.js │ └── settings.js │ ├── server │ ├── ajax.js │ ├── api.js │ ├── index.js │ ├── loadState.js │ ├── pageRendering.js │ ├── readIndexHtml.js │ ├── redirects.js │ ├── robotsRendering.js │ ├── settings.js │ ├── sitemapRendering.js │ └── themeLocales.js │ └── shared │ ├── actionTypes.js │ ├── actions.js │ ├── analytics │ ├── googleAnalytics.js │ └── index.js │ ├── app.js │ ├── components │ ├── checkoutForm │ │ ├── form.js │ │ └── index.js │ ├── paymentForm │ │ ├── LiqPay.js │ │ ├── PayPalCheckout.js │ │ └── index.js │ ├── stepContacts │ │ ├── form.js │ │ └── index.js │ ├── stepPayment │ │ ├── form.js │ │ └── index.js │ └── stepShipping │ │ ├── form.js │ │ └── index.js │ ├── containerProps.js │ ├── containers │ ├── category.js │ ├── checkout.js │ ├── checkoutSuccess.js │ ├── index.js │ ├── notfound.js │ ├── page.js │ ├── product.js │ ├── search.js │ └── shared.js │ ├── lib │ ├── helper.js │ └── jsonld.js │ ├── pageTypes.js │ ├── reducers.js │ └── text.js ├── theme ├── assets │ ├── css │ │ ├── cart.scss │ │ ├── category.scss │ │ ├── checkout.scss │ │ ├── custom.scss │ │ ├── footer.scss │ │ ├── header.scss │ │ ├── homeSlider.scss │ │ ├── page.scss │ │ ├── product.scss │ │ └── theme.scss │ ├── images │ │ ├── arrow_back.svg │ │ ├── arrow_down.svg │ │ ├── arrow_right.svg │ │ ├── close.svg │ │ ├── icons │ │ │ ├── icon-128.png │ │ │ ├── icon-16.png │ │ │ ├── icon-256.png │ │ │ ├── icon-32.png │ │ │ └── icon-512.png │ │ ├── logo.png │ │ ├── payment │ │ │ ├── alipay.svg │ │ │ ├── amex.svg │ │ │ ├── diners.svg │ │ │ ├── discover.svg │ │ │ ├── hipercard.svg │ │ │ ├── jcb.svg │ │ │ ├── maestro.svg │ │ │ ├── mastercard.svg │ │ │ ├── paypal.svg │ │ │ ├── unionpay.svg │ │ │ └── visa.svg │ │ ├── search.svg │ │ ├── shopping-bag.svg │ │ ├── slide7.jpg │ │ ├── slide8.jpg │ │ ├── slide9.jpg │ │ ├── success.svg │ │ └── thin_arrow_right.svg │ └── manifest.json ├── config │ ├── settings.json │ └── settings_schema.json ├── index.html ├── locales │ ├── en.json │ ├── ru.json │ ├── uk.json │ └── zh_CN.json ├── package-lock.json ├── package.json └── src │ ├── components │ ├── attributeFilter.js │ ├── cart.js │ ├── cartIndicator.js │ ├── categoryBreadcrumbs.js │ ├── categoryGallery.js │ ├── checkoutSuccess.js │ ├── comments │ │ └── disqus.js │ ├── disqus.js │ ├── footer.js │ ├── head │ │ ├── cart.js │ │ ├── cartIndicator.js │ │ ├── headMenu.js │ │ ├── index.js │ │ └── searchBox.js │ ├── headMenu.js │ ├── header.js │ ├── header │ │ ├── cart.js │ │ ├── cartIndicator.js │ │ ├── headMenu.js │ │ ├── index.js │ │ └── searchBox.js │ ├── homeSlider.js │ ├── metaTags.js │ ├── orderSummary.js │ ├── pageList │ │ ├── index.js │ │ ├── item.js │ │ └── list.js │ ├── priceSlider.js │ ├── productDetails │ │ ├── addToCartButton.js │ │ ├── attributes.js │ │ ├── breadcrumbs.js │ │ ├── discountCountdown.js │ │ ├── gallery.js │ │ ├── index.js │ │ ├── options.js │ │ ├── price.js │ │ ├── quantity.js │ │ ├── relatedProducts.js │ │ └── tags.js │ ├── productFilter.js │ ├── productFilter │ │ ├── attributeFilter.js │ │ ├── index.js │ │ └── priceSlider.js │ ├── productList │ │ ├── index.js │ │ ├── item.js │ │ ├── itemImage.js │ │ ├── itemPrice.js │ │ ├── itemTags.js │ │ └── loadMore.js │ ├── products │ │ ├── custom.js │ │ └── viewed.js │ ├── searchBox.js │ └── sort.js │ ├── containers │ ├── category.js │ ├── checkout.js │ ├── checkoutSuccess.js │ ├── index.js │ ├── notfound.js │ ├── page.js │ ├── product.js │ ├── search.js │ └── shared.js │ ├── index.js │ └── lib │ ├── api.js │ ├── helper.js │ └── settings.js ├── webpack.config.admin.js └── webpack.config.store.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2016 cezerin 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /config/admin.js: -------------------------------------------------------------------------------- 1 | // config used by dashboard client side only 2 | module.exports = { 3 | // dashboard UI language 4 | language: 'en', 5 | apiBaseUrl: 'http://localhost:3001/api/v1', 6 | developerMode: true 7 | } 8 | -------------------------------------------------------------------------------- /config/store.js: -------------------------------------------------------------------------------- 1 | // config used by store client side only 2 | module.exports = { 3 | // store UI language 4 | language: 'en', 5 | ajaxBaseUrl: 'http://localhost:3001/ajax' 6 | } 7 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ## Documentation 2 | 3 | ### General 4 | * [Getting Started](./getting-started.md) 5 | * [Developer Install Guide](./developer.md) 6 | * [Application Structure](./structure.md) 7 | * [Initialize MongoDB](.initialize-mongodb.md) 8 | * Theme customization 9 | * [API](https://apidocs.cezerin.com) 10 | * [API Client](https://github.com/cezerin/client) 11 | * Localization 12 | * Payment Gateway 13 | * Web Service 14 | 15 | ### Questions 16 | 17 | * How to change language 18 | 19 | ### Recipes 20 | 21 | * How to Integrate Disqus 22 | 23 | -------------------------------------------------------------------------------- /docs/structure.md: -------------------------------------------------------------------------------- 1 | ## Application Structure 2 | 3 | ``` 4 | . 5 | ├── config # Project and build configurations 6 | ├── dist # Distribution folder 7 | ├── locales # Text files 8 | ├── logs # Log files 9 | ├── public # Public static assets and uploads 10 | │ ├── admin # Dashboard index.html 11 | │ ├── admin-assets # Dashboard assets 12 | │ └── content # Store root folder 13 | | 14 | ├── scripts # Shell scripts for theme install/export 15 | ├── src # Application source code 16 | │ ├── admin # Dashboard application 17 | │ │ └── client # Client side code 18 | │ ├── api # REST API 19 | │ │ └── server # Server side code 20 | │ ├── store # Store application 21 | │ | ├── client # Client side code 22 | │ | ├── server # Server side code 23 | │ | └── shared # Universal code 24 | │ └── index.js # Server application start point 25 | ├── theme # Theme as a local package 26 | └── process.json # pm2 process file 27 | ``` 28 | -------------------------------------------------------------------------------- /locales/store/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "loading": "Loading...", 3 | "optional": "optional", 4 | "shippingTo": "Shipping To", 5 | "shippingMethods": "Shipping options", 6 | "shippingMethod": "Shipping method", 7 | "paymentMethods": "Payment options", 8 | "paymentMethod": "Payment method", 9 | "shippingAddress": "Shipping Address", 10 | "billingAddress": "Billing Address", 11 | "orderSubmit": "Place Order", 12 | "emptyCheckout": "Your cart is empty", 13 | "email": "Email", 14 | "mobile": "Mobile", 15 | "country": "Country", 16 | "state": "State/Province", 17 | "city": "City", 18 | "fullName": "Full name", 19 | "address1": "Address line 1", 20 | "address2": "Address line 2", 21 | "postal_code": "Postal code", 22 | "phone": "Phone", 23 | "company": "Company", 24 | "comments": "Comments", 25 | "required": "This field is required.", 26 | "emailInvalid": "Please enter a valid email address.", 27 | "sameAsShipping": "Same as shipping address", 28 | "edit": "Edit", 29 | "next": "Next", 30 | "customerDetails": "Customer Details", 31 | "shipping": "Shipping", 32 | "payment": "Payment" 33 | } 34 | -------------------------------------------------------------------------------- /locales/store/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "loading": "Загружается ...", 3 | "optional": "необязательно", 4 | "shippingTo": "Доставка", 5 | "shippingMethods": "Варианты доставки", 6 | "shippingMethod": "Способ доставки", 7 | "paymentMethods": "Варианты оплаты", 8 | "paymentMethod": "Способ оплаты", 9 | "shippingAddress": "Адрес доставки", 10 | "billingAddress": "Платежный адрес", 11 | "orderSubmit": "Разместить заказ", 12 | "emptyCheckout": "Ваша корзина пуста", 13 | "email": "Email", 14 | "mobile": "Мобильный", 15 | "country": "Страна", 16 | "state": "Область", 17 | "city": "Город", 18 | "fullName": "ФИО", 19 | "address1": "Адрес", 20 | "address2": "Адрес (дополнительно)", 21 | "postal_code": "Почтовый индекс", 22 | "phone": "Телефон", 23 | "company": "Название компании", 24 | "comments": "Примечание", 25 | "required": "Заполните это поле.", 26 | "emailInvalid": "Пожалуйста, введите действительный адрес электронной почты.", 27 | "sameAsShipping": "Такой же, что и адрес доставки", 28 | "edit": "Изменить", 29 | "next": "Далее", 30 | "customerDetails": "Информация о клиенте", 31 | "shipping": "Доставка", 32 | "payment": "Оплата" 33 | } 34 | -------------------------------------------------------------------------------- /locales/store/uk.json: -------------------------------------------------------------------------------- 1 | { 2 | "loading": "Завантаження ...", 3 | "optional": "не обов'язково", 4 | "shippingTo": "Доставка", 5 | "shippingMethods": "Варіанти доставки", 6 | "shippingMethod": "Спосіб доставки", 7 | "paymentMethods": "Варіанти оплати", 8 | "paymentMethod": "Спосіб оплати", 9 | "shippingAddress": "Адреса доставки", 10 | "billingAddress": "Адреса виставлення рахунку", 11 | "orderSubmit": "Замовлення підтверджую", 12 | "emptyCheckout": "Кошик порожній", 13 | "email": "Email", 14 | "mobile": "Мобільний", 15 | "country": "Країна", 16 | "state": "Область", 17 | "city": "Місто", 18 | "fullName": "ПІБ", 19 | "address1": "Адреса", 20 | "address2": "Адреса (додатково)", 21 | "postal_code": "Поштовий індекс", 22 | "phone": "Телефон", 23 | "company": "Назва компанії", 24 | "comments": "Примітка", 25 | "required": "Заповніть це поле.", 26 | "emailInvalid": "Будь ласка, введіть адресу електронної пошти.", 27 | "sameAsShipping": "Такий же, що і адреса доставки", 28 | "edit": "Змінити", 29 | "next": "Далі", 30 | "customerDetails": "Інформація про клієнта", 31 | "shipping": "Доставка", 32 | "payment": "Оплата" 33 | } 34 | -------------------------------------------------------------------------------- /locales/store/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "loading": "加载中...", 3 | "optional": "可选", 4 | "shippingTo": "送货至", 5 | "shippingMethods": "运送选项", 6 | "shippingMethod": "运送方式", 7 | "paymentMethods": "付款选项", 8 | "paymentMethod": "付款方式", 9 | "shippingAddress": "送货地址", 10 | "billingAddress": "账单地址", 11 | "orderSubmit": "下单", 12 | "emptyCheckout": "你的购物车是空的", 13 | "email": "电子邮件", 14 | "mobile": "手机", 15 | "country": "国家", 16 | "state": "省/自治区", 17 | "city": "城市", 18 | "fullName": "全名", 19 | "address1": "地址栏 1", 20 | "address2": "地址栏 2", 21 | "postal_code": "邮政编码", 22 | "phone": "电话", 23 | "company": "公司", 24 | "comments": "评论", 25 | "required": "此字段需要填写", 26 | "emailInvalid": "请输入一个有效的电子邮件地址。", 27 | "sameAsShipping": "同送货地址", 28 | "edit": "编辑", 29 | "next": "下一步", 30 | "customerDetails": "客户详情", 31 | "shipping": "运送", 32 | "payment": "付款" 33 | } 34 | -------------------------------------------------------------------------------- /logs/README.md: -------------------------------------------------------------------------------- 1 | Folder must exists 2 | -------------------------------------------------------------------------------- /process.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [{ 3 | "name": "api", 4 | "script": "./src/api/server/index.js", 5 | "watch": ["./config/server.js", "./src/api/server/"], 6 | "instances": "1", 7 | "exec_mode": "fork", 8 | "env": { 9 | "NODE_ENV": "production" 10 | }, 11 | "watch_options": { 12 | "persistent": true, 13 | "ignoreInitial": false 14 | } 15 | }, { 16 | "name": "store", 17 | "script": "./dist/store/server/index.js", 18 | "watch": ["./config/server.js", "./public/admin/index.html", "./dist/store/", "./theme/dist/", "./theme/assets/index.html"], 19 | "instances": "1", 20 | "exec_mode": "fork", 21 | "env": { 22 | "NODE_ENV": "production" 23 | }, 24 | "watch_options": { 25 | "persistent": true, 26 | "ignoreInitial": false 27 | } 28 | }] 29 | } 30 | -------------------------------------------------------------------------------- /public/admin-assets/images/apps/facebook-customer-chat-plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/images/apps/facebook-customer-chat-plugin.png -------------------------------------------------------------------------------- /public/admin-assets/images/apps/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/images/apps/facebook.png -------------------------------------------------------------------------------- /public/admin-assets/images/apps/google_analytics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/images/apps/google_analytics.png -------------------------------------------------------------------------------- /public/admin-assets/images/apps/jivosite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/images/apps/jivosite.png -------------------------------------------------------------------------------- /public/admin-assets/images/apps/messenger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/images/apps/messenger.png -------------------------------------------------------------------------------- /public/admin-assets/images/apps/site_verification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/images/apps/site_verification.png -------------------------------------------------------------------------------- /public/admin-assets/images/shortcut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/images/shortcut.png -------------------------------------------------------------------------------- /public/admin-assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Cezerin", 3 | "short_name": "Cezerin", 4 | "start_url": "/admin", 5 | "display": "standalone", 6 | "background_color": "#F9F9F9", 7 | "theme_color": "#1976D2", 8 | "icons": [{ 9 | "src": "/admin-assets/images/shortcut.png", 10 | "sizes": "96x96", 11 | "type": "image/png" 12 | },{ 13 | "src": "/admin-assets/images/shortcut.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }] 17 | } 18 | -------------------------------------------------------------------------------- /public/admin-assets/tinymce/langs/readme.md: -------------------------------------------------------------------------------- 1 | This is where language files should be placed. 2 | 3 | Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/ 4 | -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/anchor/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("anchor",function(a){function b(){var b=a.selection.getNode(),c="",d="A"==b.tagName&&""===a.dom.getAttrib(b,"href");d&&(c=b.name||b.id||""),a.windowManager.open({title:"Anchor",body:{type:"textbox",name:"name",size:40,label:"Name",value:c},onsubmit:function(c){var e=c.data.name;d?b.id=e:(a.selection.collapse(!0),a.execCommand("mceInsertContent",!1,a.dom.createHTML("a",{id:e})))}})}a.addCommand("mceAnchor",b),a.addButton("anchor",{icon:"anchor",tooltip:"Anchor",onclick:b,stateSelector:"a:not([href])"}),a.addMenuItem("anchor",{icon:"anchor",text:"Anchor",context:"insert",onclick:b})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/code/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("code",function(a){function b(){var b=a.windowManager.open({title:"Source code",body:{type:"textbox",name:"code",multiline:!0,minWidth:a.getParam("code_dialog_width",600),minHeight:a.getParam("code_dialog_height",Math.min(tinymce.DOM.getViewPort().h-200,500)),spellcheck:!1,style:"direction: ltr; text-align: left"},onSubmit:function(b){a.focus(),a.undoManager.transact(function(){a.setContent(b.data.code)}),a.selection.setCursorLocation(),a.nodeChanged()}});b.find("#code").value(a.getContent({source_view:!0}))}a.addCommand("mceCodeEditor",b),a.addButton("code",{icon:"code",tooltip:"Source code",onclick:b}),a.addMenuItem("code",{icon:"code",text:"Source code",context:"tools",onclick:b})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/colorpicker/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("colorpicker",function(a){function b(b,c){function d(a){var b=new tinymce.util.Color(a),c=b.toRgb();f.fromJSON({r:c.r,g:c.g,b:c.b,hex:b.toHex().substr(1)}),e(b.toHex())}function e(a){f.find("#preview")[0].getEl().style.background=a}var f=a.windowManager.open({title:"Color",items:{type:"container",layout:"flex",direction:"row",align:"stretch",padding:5,spacing:10,items:[{type:"colorpicker",value:c,onchange:function(){var a=this.rgb();f&&(f.find("#r").value(a.r),f.find("#g").value(a.g),f.find("#b").value(a.b),f.find("#hex").value(this.value().substr(1)),e(this.value()))}},{type:"form",padding:0,labelGap:5,defaults:{type:"textbox",size:7,value:"0",flex:1,spellcheck:!1,onchange:function(){var a,b,c=f.find("colorpicker")[0];return a=this.name(),b=this.value(),"hex"==a?(b="#"+b,d(b),void c.value(b)):(b={r:f.find("#r").value(),g:f.find("#g").value(),b:f.find("#b").value()},c.value(b),void d(b))}},items:[{name:"r",label:"R",autofocus:1},{name:"g",label:"G"},{name:"b",label:"B"},{name:"hex",label:"#",value:"000000"},{name:"preview",type:"container",border:1}]}]},onSubmit:function(){b("#"+this.toJSON().hex)}});d(c)}a.settings.color_picker_callback||(a.settings.color_picker_callback=b)}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/contextmenu/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("contextmenu",function(a){var b,c=a.settings.contextmenu_never_use_native,d=function(a){return a.ctrlKey&&!c},e=function(){return tinymce.Env.mac&&tinymce.Env.webkit};a.on("mousedown",function(b){e()&&2===b.button&&!d(b)&&a.selection.isCollapsed()&&a.once("contextmenu",function(b){a.selection.placeCaretAt(b.clientX,b.clientY)})}),a.on("contextmenu",function(c){var e;if(!d(c)){if(c.preventDefault(),e=a.settings.contextmenu||"link image inserttable | cell row column deletetable",b)b.show();else{var f=[];tinymce.each(e.split(/[ ,]/),function(b){var c=a.menuItems[b];"|"==b&&(c={text:b}),c&&(c.shortcut="",f.push(c))});for(var g=0;g'}),a+=""}),a+=""}var d=[["cool","cry","embarassed","foot-in-mouth"],["frown","innocent","kiss","laughing"],["money-mouth","sealed","smile","surprised"],["tongue-out","undecided","wink","yell"]];a.addButton("emoticons",{type:"panelbutton",panel:{role:"application",autohide:!0,html:c,onclick:function(b){var c=a.dom.getParent(b.target,"a");c&&(a.insertContent(''+c.getAttribute('),this.hide())}},tooltip:"Emoticons"})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/example/dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Custom dialog

5 | Input some text: 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/example/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("example",function(a,b){a.addButton("example",{text:"My button",icon:!1,onclick:function(){a.windowManager.open({title:"Example plugin",body:[{type:"textbox",name:"title",label:"Title"}],onsubmit:function(b){a.insertContent("Title: "+b.data.title)}})}}),a.addMenuItem("example",{text:"Example plugin",context:"tools",onclick:function(){a.windowManager.open({title:"TinyMCE site",url:b+"/dialog.html",width:600,height:400,buttons:[{text:"Insert",onclick:function(){var b=a.windowManager.getWindows()[0];a.insertContent(b.getContentWindow().document.getElementById("content").value),b.close()}},{text:"Close",onclick:"close"}]})}})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/example_dependency/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("example_dependency",function(){},["example"]); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/hr/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("hr",function(a){a.addCommand("InsertHorizontalRule",function(){a.execCommand("mceInsertContent",!1,"
")}),a.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),a.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/media/moxieplayer.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/plugins/media/moxieplayer.swf -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/nonbreaking/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("nonbreaking",function(a){var b=a.getParam("nonbreaking_force_tab");if(a.addCommand("mceNonBreaking",function(){a.insertContent(a.plugins.visualchars&&a.plugins.visualchars.state?' ':" "),a.dom.setAttrib(a.dom.select("span.mce-nbsp"),"data-mce-bogus","1")}),a.addButton("nonbreaking",{title:"Nonbreaking space",cmd:"mceNonBreaking"}),a.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),b){var c=+b>1?+b:3;a.on("keydown",function(b){if(9==b.keyCode){if(b.shiftKey)return;b.preventDefault();for(var d=0;c>d;d++)a.execCommand("mceNonBreaking")}})}}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/noneditable/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("noneditable",function(a){function b(a){return function(b){return-1!==(" "+b.attr("class")+" ").indexOf(a)}}function c(b){function c(b){var c=arguments,d=c[c.length-2];return d>0&&'"'==g.charAt(d-1)?b:''+a.dom.encode("string"==typeof c[1]?c[1]:c[0])+""}var d=f.length,g=b.content,h=tinymce.trim(e);if("raw"!=b.format){for(;d--;)g=g.replace(f[d],c);b.content=g}}var d,e,f,g="contenteditable";d=" "+tinymce.trim(a.getParam("noneditable_editable_class","mceEditable"))+" ",e=" "+tinymce.trim(a.getParam("noneditable_noneditable_class","mceNonEditable"))+" ";var h=b(d),i=b(e);f=a.getParam("noneditable_regexp"),f&&!f.length&&(f=[f]),a.on("PreInit",function(){f&&a.on("BeforeSetContent",c),a.parser.addAttributeFilter("class",function(a){for(var b,c=a.length;c--;)b=a[c],h(b)?b.attr(g,"true"):i(b)&&b.attr(g,"false")}),a.serializer.addAttributeFilter(g,function(a){for(var b,c=a.length;c--;)b=a[c],(h(b)||i(b))&&(f&&b.attr("data-mce-content")?(b.name="#text",b.type=3,b.raw=!0,b.value=b.attr("data-mce-content")):b.attr(g,null))})})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/pagebreak/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("pagebreak",function(a){var b="mce-pagebreak",c=a.getParam("pagebreak_separator",""),d=new RegExp(c.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(a){return"\\"+a}),"gi"),e='';a.addCommand("mcePageBreak",function(){a.settings.pagebreak_split_block?a.insertContent("

"+e+"

"):a.insertContent(e)}),a.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),a.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"}),a.on("ResolveName",function(c){"IMG"==c.target.nodeName&&a.dom.hasClass(c.target,b)&&(c.name="pagebreak")}),a.on("click",function(c){c=c.target,"IMG"===c.nodeName&&a.dom.hasClass(c,b)&&a.selection.select(c)}),a.on("BeforeSetContent",function(a){a.content=a.content.replace(d,e)}),a.on("PreInit",function(){a.serializer.addNodeFilter("img",function(b){for(var d,e,f=b.length;f--;)if(d=b[f],e=d.attr("class"),e&&-1!==e.indexOf("mce-pagebreak")){var g=d.parent;if(a.schema.getBlockElements()[g.name]&&a.settings.pagebreak_split_block){g.type=3,g.value=c,g.raw=!0,d.remove();continue}d.type=3,d.value=c,d.raw=!0}})})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/print/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("print",function(a){a.addCommand("mcePrint",function(){a.getWin().print()}),a.addButton("print",{title:"Print",cmd:"mcePrint"}),a.addShortcut("Meta+P","","mcePrint"),a.addMenuItem("print",{text:"Print",cmd:"mcePrint",icon:"print",shortcut:"Meta+P",context:"file"})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/save/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("save",function(a){function b(){var b;return b=tinymce.DOM.getParent(a.id,"form"),!a.getParam("save_enablewhendirty",!0)||a.isDirty()?(tinymce.triggerSave(),a.getParam("save_onsavecallback")?(a.execCallback("save_onsavecallback",a),void a.nodeChanged()):void(b?(a.setDirty(!1),b.onsubmit&&!b.onsubmit()||("function"==typeof b.submit?b.submit():c(a.translate("Error: Form submit field collision."))),a.nodeChanged()):c(a.translate("Error: No form element found.")))):void 0}function c(b){a.notificationManager.open({text:b,type:"error"})}function d(){var b=tinymce.trim(a.startContent);return a.getParam("save_oncancelcallback")?void a.execCallback("save_oncancelcallback",a):(a.setContent(b),a.undoManager.clear(),void a.nodeChanged())}function e(){var b=this;a.on("nodeChange dirty",function(){b.disabled(a.getParam("save_enablewhendirty",!0)&&!a.isDirty())})}a.addCommand("mceSave",b),a.addCommand("mceCancel",d),a.addButton("save",{icon:"save",text:"Save",cmd:"mceSave",disabled:!0,onPostRender:e}),a.addButton("cancel",{text:"Cancel",icon:!1,cmd:"mceCancel",disabled:!0,onPostRender:e}),a.addShortcut("Meta+S","","mceSave")}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/tabfocus/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("tabfocus",function(a){function b(a){9!==a.keyCode||a.ctrlKey||a.altKey||a.metaKey||a.preventDefault()}function c(b){function c(c){function f(a){return"BODY"===a.nodeName||"hidden"!=a.type&&"none"!=a.style.display&&"hidden"!=a.style.visibility&&f(a.parentNode)}function i(a){return/INPUT|TEXTAREA|BUTTON/.test(a.tagName)&&tinymce.get(b.id)&&-1!=a.tabIndex&&f(a)}if(h=d.select(":input:enabled,*[tabindex]:not(iframe)"),e(h,function(b,c){return b.id==a.id?(g=c,!1):void 0}),c>0){for(j=g+1;j=0;j--)if(i(h[j]))return h[j];return null}var g,h,i,j;if(!(9!==b.keyCode||b.ctrlKey||b.altKey||b.metaKey||b.isDefaultPrevented())&&(i=f(a.getParam("tab_focus",a.getParam("tabfocus_elements",":prev,:next"))),1==i.length&&(i[1]=i[0],i[0]=":prev"),h=b.shiftKey?":prev"==i[0]?c(-1):d.get(i[0]):":next"==i[1]?c(1):d.get(i[1]))){var k=tinymce.get(h.id||h.name);h.id&&k?k.focus():tinymce.util.Delay.setTimeout(function(){tinymce.Env.webkit||window.focus(),h.focus()},10),b.preventDefault()}}var d=tinymce.DOM,e=tinymce.each,f=tinymce.explode;a.on("init",function(){a.inline&&tinymce.DOM.setAttrib(a.getBody(),"tabIndex",null),a.on("keyup",b),tinymce.Env.gecko?a.on("keypress keydown",c):a.on("keydown",c)})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/visualblocks/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("visualblocks",function(a,b){function c(){var b=this;b.active(f),a.on("VisualBlocks",function(){b.active(a.dom.hasClass(a.getBody(),"mce-visualblocks"))})}var d,e,f;window.NodeList&&(a.addCommand("mceVisualBlocks",function(){var c,g=a.dom;d||(d=g.uniqueId(),c=g.create("link",{id:d,rel:"stylesheet",href:b+"/css/visualblocks.css"}),a.getDoc().getElementsByTagName("head")[0].appendChild(c)),a.on("PreviewFormats AfterPreviewFormats",function(b){f&&g.toggleClass(a.getBody(),"mce-visualblocks","afterpreviewformats"==b.type)}),g.toggleClass(a.getBody(),"mce-visualblocks"),f=a.dom.hasClass(a.getBody(),"mce-visualblocks"),e&&e.active(g.hasClass(a.getBody(),"mce-visualblocks")),a.fire("VisualBlocks")}),a.addButton("visualblocks",{title:"Show blocks",cmd:"mceVisualBlocks",onPostRender:c}),a.addMenuItem("visualblocks",{text:"Show blocks",cmd:"mceVisualBlocks",onPostRender:c,selectable:!0,context:"view",prependToContext:!0}),a.on("init",function(){a.settings.visualblocks_default_state&&a.execCommand("mceVisualBlocks",!1,null,{skip_focus:!0})}),a.on("remove",function(){a.dom.removeClass(a.getBody(),"mce-visualblocks")}))}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/visualchars/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("visualchars",function(a){function b(b){function c(a){return''+a+""}function f(){var a,b="";for(a in n)b+=a;return new RegExp("["+b+"]","g")}function g(){var a,b="";for(a in n)b&&(b+=","),b+="span.mce-"+n[a];return b}var h,i,j,k,l,m,n,o,p=a.getBody(),q=a.selection;if(n={"\xa0":"nbsp","\xad":"shy"},d=!d,e.state=d,a.fire("VisualChars",{state:d}),o=f(),b&&(m=q.getBookmark()),d)for(i=[],tinymce.walk(p,function(a){3==a.nodeType&&a.nodeValue&&o.test(a.nodeValue)&&i.push(a)},"childNodes"),j=0;j=0;j--)a.dom.remove(i[j],1);q.moveToBookmark(m)}function c(){var b=this;a.on("VisualChars",function(a){b.active(a.state)})}var d,e=this;a.addCommand("mceVisualChars",b),a.addButton("visualchars",{title:"Show invisible characters",cmd:"mceVisualChars",onPostRender:c}),a.addMenuItem("visualchars",{text:"Show invisible characters",cmd:"mceVisualChars",onPostRender:c,selectable:!0,context:"view",prependToContext:!0}),a.on("beforegetcontent",function(a){d&&"raw"!=a.format&&!a.draft&&(d=!0,b(!1))})}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/plugins/wordcount/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("wordcount",function(a){function b(){a.theme.panel.find("#wordcount").text(["Words: {0}",e.getCount()])}var c,d,e=this;c=a.getParam("wordcount_countregex",/[\w\u2019\x27\-\u00C0-\u1FFF]+/g),d=a.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$?\x27\x22_+=\\\/\-]*/g),a.on("init",function(){var c=a.theme.panel&&a.theme.panel.find("#statusbar")[0];c&&tinymce.util.Delay.setEditorTimeout(a,function(){c.insert({type:"label",name:"wordcount",text:["Words: {0}",e.getCount()],classes:"wordcount",disabled:a.settings.readonly},0),a.on("setcontent beforeaddundo",b),a.on("keyup",function(a){32==a.keyCode&&b()})},0)}),e.getCount=function(){var b=a.getContent({format:"raw"}),e=0;if(b){b=b.replace(/\.\.\./g," "),b=b.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," "),b=b.replace(/(\w+)(&#?[a-z0-9]+;)+(\w+)/i,"$1$3").replace(/&.+?;/g," "),b=b.replace(d,"");var f=b.match(c);f&&(e=f.length)}return e}}); -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/fonts/tinymce-small.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/fonts/tinymce-small.eot -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/fonts/tinymce-small.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/fonts/tinymce-small.ttf -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/fonts/tinymce-small.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/fonts/tinymce-small.woff -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/fonts/tinymce.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/fonts/tinymce.eot -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/fonts/tinymce.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/fonts/tinymce.ttf -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/fonts/tinymce.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/fonts/tinymce.woff -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/img/anchor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/img/anchor.gif -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/img/loader.gif -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/img/object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/img/object.gif -------------------------------------------------------------------------------- /public/admin-assets/tinymce/skins/lightgray/img/trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/public/admin-assets/tinymce/skins/lightgray/img/trans.gif -------------------------------------------------------------------------------- /public/content/README.md: -------------------------------------------------------------------------------- 1 | Folder must exists 2 | -------------------------------------------------------------------------------- /public/robots.template: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /api 3 | Disallow: /admin 4 | Disallow: /cart 5 | Disallow: /checkout 6 | Disallow: /checkout-success 7 | Disallow: /register 8 | Disallow: /login 9 | Disallow: /logout 10 | Disallow: /account 11 | Disallow: /settings 12 | Disallow: /search 13 | Sitemap: {domain}/sitemap.xml 14 | Host: {domain} 15 | -------------------------------------------------------------------------------- /public/sw.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | importScripts('/sw-toolbox.js'); 3 | toolbox.router.get('/images/*', toolbox.cacheFirst); 4 | toolbox.router.get('/assets/*', toolbox.cacheFirst); 5 | toolbox.router.get('/admin-assets/*', toolbox.cacheFirst); 6 | toolbox.router.get('/api/*', toolbox.networkOnly); 7 | toolbox.router.get('/ajax/payment_form_settings', toolbox.networkOnly); 8 | toolbox.router.get('/*', toolbox.networkFirst, { networkTimeoutSeconds: 5}); 9 | -------------------------------------------------------------------------------- /scripts/theme-export.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # first argument is *.zip file name 5 | fileName="theme.zip" 6 | 7 | # 1. change fileName if arg passed 8 | if [ $# -ne 0 ]; then 9 | fileName=$1 10 | fi 11 | 12 | # 2. delete zip if exists 13 | if [ -f "public/content/$fileName" ]; then 14 | rm public/content/$fileName 15 | fi 16 | 17 | # 3. zip current theme 18 | cd theme 19 | zip -rq9 ../public/content/$fileName . -x node_modules\* dist\* assets/index.html assets/js/bundle-\* assets/css/bundle-\* 20 | 21 | # 4. show success message 22 | echo success 23 | -------------------------------------------------------------------------------- /scripts/theme-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # first argument is *.zip file name 5 | fileName=$1 6 | 7 | if [ $# -eq 0 ]; then 8 | echo "No arguments supplied" 9 | exit 1 10 | fi 11 | 12 | # 1. check file exists 13 | if [ ! -f "public/content/$fileName" ]; then 14 | echo "File not found!" 15 | exit 1 16 | fi 17 | 18 | # 3. remove all the contents of theme folder 19 | rm -rf theme/* 20 | 21 | # 4. unzip to current theme 22 | unzip -q "public/content/$fileName" -d "theme" 23 | 24 | # 5. build theme 25 | npm run theme:build:prod 26 | 27 | # 6. show success message 28 | echo -e '\e[1;92m'Theme $fileName successfully installed'\e[0m' 29 | -------------------------------------------------------------------------------- /src/admin/client/apps/index.js: -------------------------------------------------------------------------------- 1 | import * as GoogleAnalyticsApp from './google-analytics' 2 | import * as SiteVerificationApp from './site-verification' 3 | import * as JivositeApp from './jivosite' 4 | import * as FacebookSDKApp from './facebook-sdk' 5 | import * as FacebookCustomerChatApp from './facebook-customer-chat' 6 | 7 | export default [GoogleAnalyticsApp, SiteVerificationApp, JivositeApp, FacebookSDKApp, FacebookCustomerChatApp]; 8 | -------------------------------------------------------------------------------- /src/admin/client/index.js: -------------------------------------------------------------------------------- 1 | import '../../../public/admin-assets/css/flexboxgrid.min.css' 2 | import '../../../public/admin-assets/css/style.css' 3 | 4 | import React from 'react' 5 | import ReactDOM from 'react-dom' 6 | import {createStore, applyMiddleware} from 'redux' 7 | import {Provider} from 'react-redux' 8 | import thunkMiddleware from 'redux-thunk' 9 | 10 | import {fetchSettings} from 'modules/settings/actions' 11 | import settings from 'lib/settings' 12 | import * as auth from 'lib/auth' 13 | import {listenEvents} from 'lib/events' 14 | import reducers from './rootReducer' 15 | import App from './app' 16 | 17 | const DEVELOPER_MODE = settings.developerMode === true; 18 | if(DEVELOPER_MODE === false){ 19 | auth.validateCurrentToken(); 20 | } 21 | 22 | const store = createStore(reducers, applyMiddleware(thunkMiddleware)); 23 | store.dispatch(fetchSettings()); 24 | 25 | if (!!window.EventSource) { 26 | listenEvents(store); 27 | } 28 | 29 | ReactDOM.render( 30 | 31 | 32 | , 33 | document.getElementById('app')); 34 | -------------------------------------------------------------------------------- /src/admin/client/lib/api.js: -------------------------------------------------------------------------------- 1 | import CezerinClient from 'cezerin-client' 2 | import settings from 'lib/settings' 3 | 4 | let api = null; 5 | let dashboardToken = localStorage.getItem('dashboard_token'); 6 | let webstoreToken = localStorage.getItem('webstore_token'); 7 | 8 | const DEVELOPER_MODE = settings.developerMode === true; 9 | 10 | if(dashboardToken || DEVELOPER_MODE === true) { 11 | api = new CezerinClient({ 12 | apiBaseUrl: settings.apiBaseUrl || '/api/v1', 13 | apiToken: dashboardToken, 14 | webstoreToken: webstoreToken 15 | }); 16 | } 17 | 18 | export default api; 19 | -------------------------------------------------------------------------------- /src/admin/client/lib/data.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | countries: APPLICATION_DATA_COUNTRIES, 3 | currencies: APPLICATION_DATA_CURRENCIES, 4 | timezones: APPLICATION_DATA_TIMEZONES 5 | } 6 | -------------------------------------------------------------------------------- /src/admin/client/lib/events.js: -------------------------------------------------------------------------------- 1 | import {fetchSettings, installReceive} from 'modules/settings/actions' 2 | import {fetchOrders} from 'modules/orders/actions' 3 | 4 | const THEME_INSTALLED = 'theme-installed'; 5 | const ORDER_RECEIVED = 'order-received'; 6 | const ORDER_CHANGED = 'order-changed'; 7 | 8 | const messageReceived = (message, store) => { 9 | switch(message.type){ 10 | case THEME_INSTALLED: 11 | store.dispatch(installReceive()); 12 | break; 13 | case ORDER_RECEIVED: 14 | store.dispatch(fetchOrders()); 15 | break; 16 | default: 17 | break; 18 | } 19 | } 20 | 21 | export const listenEvents = (store) => { 22 | const eventsUrl = '/api/dashboard/events?token=' + localStorage.getItem('dashboard_token'); 23 | const serverEvents = new EventSource(eventsUrl); 24 | 25 | serverEvents.onmessage = (e) => { 26 | if(e.origin === location.origin && e.isTrusted === true){ 27 | const message = JSON.parse(e.data); 28 | messageReceived(message, store); 29 | } else { 30 | console.log('Received message from server: ' + e.origin); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/admin/client/lib/settings.js: -------------------------------------------------------------------------------- 1 | module.exports = APPLICATION_CONFIG; 2 | -------------------------------------------------------------------------------- /src/admin/client/lib/text.js: -------------------------------------------------------------------------------- 1 | module.exports = APPLICATION_TEXT; 2 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/account/components/details.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import messages from 'lib/text' 3 | import style from './style.css' 4 | import Account from './account' 5 | import Developer from './developer' 6 | 7 | export default class WebStoreAccountDetails extends React.Component { 8 | constructor(props) { 9 | super(props) 10 | } 11 | 12 | componentDidMount() { 13 | this.props.fetchData(); 14 | } 15 | 16 | render() { 17 | const { account, onAccountSubmit, onDeveloperSubmit } = this.props; 18 | const developerData = account ? account.developer : null; 19 | 20 | if(account){ 21 | return ( 22 |
23 | 24 | {account && account.is_developer === true && 25 | 26 | } 27 |
28 | ) 29 | } else { 30 | return null; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/account/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .toggle { 6 | margin-top: 12px; 7 | margin-bottom: 22px; 8 | } 9 | 10 | .innerBox { 11 | padding: 30px; 12 | } 13 | 14 | .childrenBox { 15 | padding: 0 30px 30px 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | 22 | .detailsContainer { 23 | display: flex; 24 | flex-direction: column; 25 | align-items: center; 26 | } 27 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/account/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchAccount, updateAccount, updateDeveloperAccount } from '../actions' 3 | import Details from './components/details' 4 | import * as webstoreAuth from 'lib/webstoreAuth' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | account: state.apps.account 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch, ownProps) => { 13 | return { 14 | fetchData: () => { 15 | const webstoreAuthorized = webstoreAuth.isCurrentTokenValid(); 16 | if(webstoreAuthorized){ 17 | dispatch(fetchAccount()) 18 | } else { 19 | ownProps.history.push('/admin/apps/login'); 20 | } 21 | }, 22 | onAccountSubmit: (values) => { 23 | dispatch(updateAccount(values)); 24 | }, 25 | onDeveloperSubmit: (values) => { 26 | dispatch(updateDeveloperAccount(values)); 27 | } 28 | } 29 | } 30 | 31 | export default connect(mapStateToProps, mapDispatchToProps)(Details); 32 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const ACCOUNT_REQUEST = 'ACCOUNT_REQUEST' 2 | export const ACCOUNT_RECEIVE = 'ACCOUNT_RECEIVE' 3 | 4 | export const SERVICES_REQUEST = 'SERVICES_REQUEST' 5 | export const SERVICES_RECEIVE = 'SERVICES_RECEIVE' 6 | 7 | export const SERVICE_REQUEST = 'SERVICE_REQUEST' 8 | export const SERVICE_RECEIVE = 'SERVICE_RECEIVE' 9 | 10 | export const SERVICE_ENABLE_REQUEST = 'SERVICE_ENABLE_REQUEST' 11 | export const SERVICE_ENABLE_RECEIVE = 'SERVICE_ENABLE_RECEIVE' 12 | 13 | export const SERVICE_SETTINGS_REQUEST = 'SERVICE_SETTINGS_REQUEST' 14 | export const SERVICE_SETTINGS_RECEIVE = 'SERVICE_SETTINGS_RECEIVE' 15 | 16 | export const SERVICE_LOGS_REQUEST = 'SERVICE_LOGS_REQUEST' 17 | export const SERVICE_LOGS_RECEIVE = 'SERVICE_LOGS_RECEIVE' 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/appDetails/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import AppDescription from './description' 3 | import style from './style.css' 4 | import Paper from 'material-ui/Paper' 5 | import apps from 'src/apps' 6 | 7 | const AppDetails = ({ match }) => { 8 | const { appKey } = match.params; 9 | const app = apps.find(a => a.Description.key === appKey); 10 | const AppModule = app.App; 11 | const appDescription = app.Description; 12 | 13 | return ( 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 |
22 |
23 |
24 | ) 25 | } 26 | 27 | export default AppDetails; 28 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/head/components/buttons.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import messages from 'lib/text' 4 | 5 | import FontIcon from 'material-ui/FontIcon'; 6 | import IconMenu from 'material-ui/IconMenu'; 7 | import IconButton from 'material-ui/IconButton'; 8 | import MenuItem from 'material-ui/MenuItem'; 9 | 10 | const WebStoreMenu = () => { 11 | return ( 12 | 15 | more_vert 16 | 17 | } 18 | targetOrigin={{horizontal: 'right', vertical: 'top'}} 19 | anchorOrigin={{horizontal: 'right', vertical: 'top'}} 20 | > 21 | } primaryText={messages.account} /> 22 | 23 | ) 24 | } 25 | 26 | export default WebStoreMenu; 27 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/head/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { withRouter } from 'react-router' 4 | import Buttons from './components/buttons' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return {} 8 | } 9 | 10 | const mapDispatchToProps = (dispatch, ownProps) => { 11 | return {} 12 | } 13 | 14 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 15 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/reducer.js: -------------------------------------------------------------------------------- 1 | import * as t from './actionTypes' 2 | 3 | const initialState = { 4 | account: null, 5 | services: [], 6 | service: null, 7 | serviceSettings: null, 8 | serviceLogs: null, 9 | loadingEnableDisableService: false 10 | }; 11 | 12 | export default(state = initialState, action) => { 13 | switch (action.type) { 14 | case t.ACCOUNT_RECEIVE: 15 | return Object.assign({}, state, {account: action.account}) 16 | case t.SERVICES_RECEIVE: 17 | return Object.assign({}, state, {services: action.services}) 18 | case t.SERVICE_RECEIVE: 19 | return Object.assign({}, state, {service: action.service}) 20 | case t.SERVICE_SETTINGS_REQUEST: 21 | return Object.assign({}, state, {serviceSettings: null}) 22 | case t.SERVICE_SETTINGS_RECEIVE: 23 | return Object.assign({}, state, {serviceSettings: action.serviceSettings}) 24 | case t.SERVICE_LOGS_RECEIVE: 25 | return Object.assign({}, state, {serviceLogs: action.serviceLogs}) 26 | case t.SERVICE_ENABLE_REQUEST: 27 | return Object.assign({}, state, {loadingEnableDisableService: true}) 28 | case t.SERVICE_ENABLE_RECEIVE: 29 | return Object.assign({}, state, {loadingEnableDisableService: false}) 30 | default: 31 | return state 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/serviceDetails/components/logs.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Link} from 'react-router-dom' 3 | import moment from 'moment' 4 | 5 | import messages from 'lib/text' 6 | import api from 'lib/api' 7 | import style from './style.css' 8 | import Paper from 'material-ui/Paper'; 9 | 10 | const ServiceLogs = ({ logs }) => { 11 | const list = logs.map((action, index) => { 12 | const date = moment(action.date); 13 | const dateFormated = date.fromNow(); 14 | return ( 15 |
16 |
{action.message}
17 |
{dateFormated}
18 |
19 | ) 20 | }); 21 | 22 | return ( 23 |
24 |
{messages.serviceLogs}
25 | 26 |
27 | {list} 28 |
29 |
30 |
31 | ) 32 | } 33 | 34 | export default ServiceLogs; 35 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/services/components/appItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Item from './item' 3 | 4 | const ServiceItem = ({ app }) => { 5 | return ( 6 | 11 | ) 12 | } 13 | 14 | export default ServiceItem; 15 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/services/components/serviceItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Item from './item' 3 | 4 | const ServiceItem = ({ service }) => { 5 | return ( 6 | 13 | ) 14 | } 15 | 16 | export default ServiceItem; 17 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/services/components/style.css: -------------------------------------------------------------------------------- 1 | .servicesCover { 2 | width: 280px; 3 | height: 160px; 4 | background-size: cover; 5 | background-position: center; 6 | border-radius: 2px 2px 0 0; 7 | } 8 | 9 | .more { 10 | padding: 40px 0; 11 | text-align: center; 12 | } 13 | 14 | .card:hover { 15 | box-shadow: 0 2px 2px 0 rgba(0,0,0,0.2), 0 6px 10px 0 rgba(0,0,0,0.3) !important; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/client/modules/apps/services/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { fetchServices } from '../actions' 4 | import * as webstoreAuth from 'lib/webstoreAuth' 5 | import List from './components/list' 6 | 7 | const mapStateToProps = (state, ownProps) => { 8 | const webstoreAuthorized = webstoreAuth.isCurrentTokenValid(); 9 | return { 10 | services: state.apps.services, 11 | webstoreAuthorized: webstoreAuthorized 12 | } 13 | } 14 | 15 | const mapDispatchToProps = (dispatch, ownProps) => { 16 | return { 17 | fetchData: () => { 18 | dispatch(fetchServices()); 19 | } 20 | } 21 | } 22 | 23 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(List)); 24 | -------------------------------------------------------------------------------- /src/admin/client/modules/customerGroups/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const GROUPS_REQUEST = 'GROUPS_REQUEST' 2 | export const GROUPS_RECEIVE = 'GROUPS_RECEIVE' 3 | export const GROUPS_FAILURE = 'GROUPS_FAILURE' 4 | 5 | export const GROUPS_SELECT = 'GROUPS_SELECT' 6 | export const GROUPS_DESELECT = 'GROUPS_DESELECT' 7 | 8 | export const GROUP_UPDATE_REQUEST = 'GROUP_UPDATE_REQUEST' 9 | export const GROUP_UPDATE_SUCCESS = 'GROUP_UPDATE_SUCCESS' 10 | export const GROUP_UPDATE_FAILURE = 'GROUP_UPDATE_FAILURE' 11 | 12 | export const GROUP_CREATE_SUCCESS = 'GROUP_CREATE_SUCCESS' 13 | export const GROUP_DELETE_SUCCESS = 'GROUP_DELETE_SUCCESS' 14 | -------------------------------------------------------------------------------- /src/admin/client/modules/customerGroups/edit/components/style.css: -------------------------------------------------------------------------------- 1 | .shortBox { 2 | max-width: 300px; 3 | } 4 | 5 | .button { 6 | margin-left: 12px; 7 | } 8 | 9 | .toggle { 10 | margin-top: 12px; 11 | margin-bottom: 22px; 12 | } 13 | 14 | .innerBox { 15 | padding: 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/customerGroups/edit/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { reset } from 'redux-form'; 3 | import { updateGroup, createGroup, deselectGroup } from '../actions' 4 | import Form from './components/form' 5 | 6 | const mapStateToProps = (state) => { 7 | return { 8 | groupId: state.customerGroups.selectedId, 9 | items: state.customerGroups.items, 10 | initialValues: state.customerGroups.items.find((item) => (item.id === state.customerGroups.selectedId)), 11 | isSaving: state.customerGroups.isSaving 12 | } 13 | } 14 | 15 | const mapDispatchToProps = (dispatch) => { 16 | return { 17 | onSubmit: (values) => { 18 | if(values.id) { 19 | dispatch(updateGroup(values)); 20 | } else { 21 | dispatch(createGroup(values)); 22 | } 23 | }, 24 | onCancel: () => { 25 | dispatch(deselectGroup()); 26 | dispatch(reset('FormCustomerGroup')); 27 | } 28 | } 29 | } 30 | 31 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 32 | -------------------------------------------------------------------------------- /src/admin/client/modules/customerGroups/head/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { reset } from 'redux-form'; 4 | import { deleteGroup, deselectGroup } from '../actions' 5 | import Buttons from './components/buttons' 6 | 7 | const mapStateToProps = (state) => { 8 | return { 9 | selected: state.customerGroups.items.find(item => item.id === state.customerGroups.selectedId) 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch) => { 14 | return { 15 | onDelete: (id) => { 16 | dispatch(deleteGroup(id)); 17 | dispatch(reset('FormCustomerGroup')); 18 | }, 19 | onCreate: () => { 20 | dispatch(deselectGroup()) 21 | } 22 | } 23 | } 24 | 25 | export default connect(mapStateToProps, mapDispatchToProps)(Buttons); 26 | -------------------------------------------------------------------------------- /src/admin/client/modules/customerGroups/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { selectGroup, fetchGroupsIfNeeded } from '../actions' 3 | import { fetchCustomers } from '../../customers/actions' 4 | import List from '../components/list' 5 | 6 | const mapStateToProps = (state) => { 7 | return { 8 | items: state.customerGroups.items, 9 | selectedId: state.customerGroups.selectedId 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch) => { 14 | return { 15 | onLoad: () => { 16 | dispatch(fetchGroupsIfNeeded()); 17 | }, 18 | onSelect: (groupId) => { 19 | dispatch(selectGroup(groupId)); 20 | dispatch(fetchCustomers()); 21 | } 22 | } 23 | } 24 | 25 | export default connect(mapStateToProps, mapDispatchToProps)(List); 26 | -------------------------------------------------------------------------------- /src/admin/client/modules/customerGroups/select/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchGroupsIfNeeded } from '../actions' 3 | import List from '../components/list' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | items: state.customerGroups.items 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchGroupsIfNeeded()); 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(List); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const CUSTOMERS_REQUEST = 'CUSTOMERS_REQUEST' 2 | export const CUSTOMERS_RECEIVE = 'CUSTOMERS_RECEIVE' 3 | export const CUSTOMERS_FAILURE = 'CUSTOMERS_FAILURE' 4 | 5 | export const CUSTOMERS_DETAIL_REQUEST = 'CUSTOMERS_DETAIL_REQUEST' 6 | export const CUSTOMERS_DETAIL_RECEIVE = 'CUSTOMERS_DETAIL_RECEIVE' 7 | export const CUSTOMERS_DETAIL_FAILURE = 'CUSTOMERS_DETAIL_FAILURE' 8 | 9 | export const CUSTOMERS_MORE_REQUEST = 'CUSTOMERS_MORE_REQUEST' 10 | export const CUSTOMERS_MORE_RECEIVE = 'CUSTOMERS_MORE_RECEIVE' 11 | 12 | export const CUSTOMERS_FILTER_SET_SEARCH = 'CUSTOMERS_FILTER_SET_SEARCH' 13 | 14 | export const CUSTOMERS_SELECT = 'CUSTOMERS_SELECT' 15 | export const CUSTOMERS_DESELECT = 'CUSTOMERS_DESELECT' 16 | export const CUSTOMERS_SELECT_ALL = 'CUSTOMERS_SELECT_ALL' 17 | export const CUSTOMERS_DESELECT_ALL = 'CUSTOMERS_DESELECT_ALL' 18 | 19 | export const CUSTOMER_DELETE_SUCCESS = 'CUSTOMER_DELETE_SUCCESS' 20 | export const CUSTOMER_SET_GROUP_SUCCESS = 'CUSTOMER_SET_GROUP_SUCCESS' 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/filter/components/style.css: -------------------------------------------------------------------------------- 1 | .filter { 2 | padding: 0 16px; 3 | } 4 | 5 | .toggle { 6 | margin-bottom: 16px; 7 | } 8 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/filter/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchProducts, setFilterActive, setFilterDiscontinued, setFilterOnSale, setFilterStock } from '../actions' 3 | import Filter from './components/fields' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | active: state.products.filter_active, 8 | discontinued: state.products.filter_discontinued, 9 | on_sale: state.products.filter_on_sale, 10 | stock_status: state.products.filter_stock_status 11 | } 12 | } 13 | 14 | const mapDispatchToProps = (dispatch) => { 15 | return { 16 | setActive: (value) => { 17 | dispatch(setFilterActive(value)); 18 | dispatch(fetchProducts()); 19 | }, 20 | setDiscontinued: (value) => { 21 | dispatch(setFilterDiscontinued(value)); 22 | dispatch(fetchProducts()); 23 | }, 24 | setOnSale: (value) => { 25 | dispatch(setFilterOnSale(value)); 26 | dispatch(fetchProducts()); 27 | }, 28 | setStock: (value) => { 29 | dispatch(setFilterStock(value)); 30 | dispatch(fetchProducts()); 31 | } 32 | } 33 | } 34 | 35 | export default connect(mapStateToProps, mapDispatchToProps)(Filter); 36 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/list/components/head.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Subheader from 'material-ui/Subheader'; 3 | import Checkbox from 'material-ui/Checkbox'; 4 | import messages from 'lib/text' 5 | 6 | export default ({ onSelectAll }) => ( 7 | 8 |
9 |
10 | { onSelectAll(isInputChecked); }} /> 11 |
12 |
13 | {messages.customers_name} 14 |
15 |
16 | {messages.customers_location} 17 |
18 |
19 | {messages.customers_orders} 20 |
21 |
22 | {messages.customers_totalSpent} 23 |
24 |
25 |
26 | ) 27 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/list/components/style.css: -------------------------------------------------------------------------------- 1 | .customerName { 2 | text-decoration: none; 3 | font-weight: 400; 4 | color: rgb(0,142,180); 5 | } 6 | 7 | .customerName small { 8 | color: rgba(0, 0, 0, 0.4); 9 | } 10 | 11 | .location { 12 | color: rgba(0, 0, 0, 0.4); 13 | } 14 | 15 | .price { 16 | word-break: break-all; 17 | text-align: right; 18 | margin-right: 10px; 19 | } 20 | 21 | .more { 22 | padding: 40px 0; 23 | text-align: center; 24 | } 25 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchCustomers, selectCustomer, deselectCustomer, selectAllCustomer, deselectAllCustomer, fetchMoreCustomers } from '../actions' 3 | import List from './components/list' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | settings: state.settings.settings, 8 | items: state.customers.items, 9 | selected: state.customers.selected, 10 | loadingItems: state.customers.loadingItems, 11 | hasMore: state.customers.hasMore 12 | } 13 | } 14 | 15 | const mapDispatchToProps = (dispatch) => { 16 | return { 17 | onLoad: () => { 18 | dispatch(fetchCustomers()); 19 | }, 20 | onSelect: (customerId, checked) => { 21 | if(checked) { 22 | dispatch(selectCustomer(customerId)); 23 | } else { 24 | dispatch(deselectCustomer(customerId)); 25 | } 26 | }, 27 | onSelectAll: (checked) => { 28 | if(checked) { 29 | dispatch(selectAllCustomer()); 30 | } else { 31 | dispatch(deselectAllCustomer()); 32 | } 33 | }, 34 | loadMore: () => { 35 | dispatch(fetchMoreCustomers()); 36 | } 37 | } 38 | } 39 | 40 | export default connect(mapStateToProps, mapDispatchToProps)(List); 41 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/listHead/components/search.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import messages from 'lib/text' 3 | import TextField from 'material-ui/TextField'; 4 | 5 | export default ({ value, setSearch }) => { 6 | return ( 7 | { setSearch(v); }} 10 | hintText={messages.customers_search} 11 | underlineShow={false} 12 | style={{ float: 'left', marginRight: 10 }} 13 | hintStyle={{ color: 'rgba(255,255,255,0.4)', textIndent: '16px' }} 14 | inputStyle={{ color:'#fff', backgroundColor: 'rgba(255,255,255,0.2)', borderRadius: '4px', textIndent: '16px' }} 15 | /> 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/customers/listHead/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { fetchCustomers, deleteCustomers, setGroup, setFilterSearch } from '../actions' 4 | import Buttons from './components/buttons' 5 | 6 | const mapStateToProps = (state) => { 7 | return { 8 | search: state.customers.search, 9 | selectedCount: state.customers.selected.length 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch) => { 14 | return { 15 | setSearch: (value) => { 16 | dispatch(setFilterSearch(value)); 17 | dispatch(fetchCustomers()); 18 | }, 19 | onDelete: () => { 20 | dispatch(deleteCustomers()); 21 | }, 22 | onSetGroup: (group_id) => { 23 | dispatch(setGroup(group_id)); 24 | } 25 | } 26 | } 27 | 28 | export default connect(mapStateToProps, mapDispatchToProps)(Buttons); 29 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const FILES_REQUEST = 'FILES_REQUEST' 2 | export const FILES_RECEIVE = 'FILES_RECEIVE' 3 | 4 | export const FILES_UPLOAD_START = 'FILES_UPLOAD_START' 5 | export const FILES_UPLOAD_END = 'FILES_UPLOAD_END' 6 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/actions.js: -------------------------------------------------------------------------------- 1 | import * as t from './actionTypes' 2 | import api from 'lib/api' 3 | import messages from 'lib/text' 4 | 5 | function receiveFiles(files) { 6 | return { 7 | type: t.FILES_RECEIVE, 8 | files 9 | } 10 | } 11 | 12 | function filesUploadStart() { 13 | return { 14 | type: t.FILES_UPLOAD_START 15 | } 16 | } 17 | 18 | function filesUploadEnd() { 19 | return { 20 | type: t.FILES_UPLOAD_END 21 | } 22 | } 23 | 24 | export function fetchFiles() { 25 | return (dispatch, getState) => { 26 | return api.files.list().then(({status, json}) => { 27 | dispatch(receiveFiles(json)) 28 | }).catch(error => {}); 29 | } 30 | } 31 | 32 | export function uploadFiles(form) { 33 | return (dispatch, getState) => { 34 | dispatch(filesUploadStart()); 35 | return api.files.upload(form).then(() => { 36 | dispatch(filesUploadEnd()); 37 | dispatch(fetchFiles()) 38 | }).catch(error => { 39 | dispatch(filesUploadEnd()); 40 | }); 41 | } 42 | } 43 | 44 | export function deleteFile(fileName) { 45 | return (dispatch, getState) => { 46 | return api.files.delete(fileName).then(() => { 47 | dispatch(fetchFiles()) 48 | }).catch(error => {}); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/list/components/fileUploader/style.css: -------------------------------------------------------------------------------- 1 | .dropzone { 2 | margin: 20px; 3 | opacity: 1; 4 | transition: opacity .2s ease-in-out; 5 | } 6 | .uploading { 7 | opacity: 0; 8 | } 9 | .dropzoneEmpty { 10 | color: #a1a1a1; 11 | font-size: 16px; 12 | border: 2px dashed rgba(0,0,0,0.1); 13 | padding: 80px 0; 14 | text-align: center; 15 | } 16 | .dropzoneActive { 17 | background-color: rgba(18,179,117, 0.4); 18 | } 19 | .dropzoneReject { 20 | background-color: rgba(244,67,54,0.8); 21 | } 22 | .dropzoneReject .list, 23 | .dropzoneActive .list { 24 | opacity: 0.3 25 | } 26 | .dropzoneActive .button { 27 | opacity: 0; 28 | } 29 | .button { 30 | margin-left: 10px !important; 31 | } 32 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/list/components/headButtons.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import messages from 'lib/text' 4 | import FontIcon from 'material-ui/FontIcon' 5 | import IconButton from 'material-ui/IconButton' 6 | 7 | const Buttons = () => null; 8 | 9 | export default Buttons; 10 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/list/components/style.css: -------------------------------------------------------------------------------- 1 | .item { 2 | font-size: 14px; 3 | padding: 4px 10px; 4 | border-bottom: 1px solid rgb(224, 224, 224); 5 | } 6 | 7 | .item:last-of-type { 8 | border-bottom: none; 9 | } 10 | 11 | .item:hover{ 12 | background-color: rgba(0, 0, 0, 0.05); 13 | } 14 | 15 | .name a { 16 | color: rgb(0,142,180); 17 | text-decoration: none; 18 | overflow: hidden; 19 | text-overflow: ellipsis; 20 | white-space: nowrap; 21 | display: block; 22 | } 23 | 24 | .name a:hover { 25 | text-decoration: underline; 26 | } 27 | 28 | .date, .size { 29 | color: rgba(0, 0, 0, 0.54); 30 | text-align: right; 31 | } 32 | 33 | .more { 34 | text-align: right; 35 | } 36 | 37 | .head { 38 | color: rgba(0, 0, 0, 0.54); 39 | font-size: 14px; 40 | font-weight: 500; 41 | padding: 16px 16px 0 26px; 42 | text-align: right; 43 | } 44 | 45 | .head div:first-of-type { 46 | text-align: left; 47 | } 48 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/list/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import Buttons from './components/headButtons' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return {} 7 | } 8 | 9 | const mapDispatchToProps = (dispatch, ownProps) => { 10 | return {} 11 | } 12 | 13 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 14 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchFiles, uploadFiles, deleteFile } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | files: state.files.files, 8 | uploading: state.files.uploading, 9 | settings: state.settings.settings 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch) => { 14 | return { 15 | onLoad: () => { 16 | dispatch(fetchFiles()) 17 | }, 18 | onDelete: (fileName) => { 19 | dispatch(deleteFile(fileName)); 20 | }, 21 | onUpload: (form) => { 22 | dispatch(uploadFiles(form)); 23 | } 24 | } 25 | } 26 | 27 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 28 | -------------------------------------------------------------------------------- /src/admin/client/modules/files/reducer.js: -------------------------------------------------------------------------------- 1 | import * as t from './actionTypes' 2 | 3 | const initialState = { 4 | files: [], 5 | uploading: false 6 | }; 7 | 8 | export default(state = initialState, action) => { 9 | switch (action.type) { 10 | case t.FILES_RECEIVE: 11 | return Object.assign({}, state, {files: action.files}) 12 | case t.FILES_UPLOAD_START: 13 | return Object.assign({}, state, { 14 | uploading: true 15 | }) 16 | case t.FILES_UPLOAD_END: 17 | return Object.assign({}, state, { 18 | uploading: false 19 | }) 20 | default: 21 | return state 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/admin/client/modules/head/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import AppBar from './components/appBar' 4 | 5 | const mapStateToProps = (state) => { 6 | const productCategory = state.productCategories.items.find((item) => (item.id === state.productCategories.selectedId)); 7 | const customerGroup = state.customerGroups.items.find((item) => (item.id === state.customerGroups.selectedId)); 8 | const orderStatus = state.orderStatuses.items.find((item) => (item.id === state.orderStatuses.selectedId)); 9 | const orderNumber = state.orders.editOrder ? state.orders.editOrder.number : null; 10 | 11 | return { 12 | productsSelectedCount: state.products.selected.length, 13 | customersSelectedCount: state.customers.selected.length, 14 | ordersSelectedCount: state.orders.selected.length, 15 | productCategoryName: productCategory ? productCategory.name : null, 16 | customerGroupName: customerGroup ? customerGroup.name : null, 17 | orderStatusName: orderStatus ? orderStatus.name: null, 18 | orderNumber: orderNumber 19 | } 20 | } 21 | 22 | const mapDispatchToProps = (dispatch) => { 23 | return {} 24 | } 25 | 26 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(AppBar)); 27 | -------------------------------------------------------------------------------- /src/admin/client/modules/orderStatuses/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const STATUSES_REQUEST = 'STATUSES_REQUEST' 2 | export const STATUSES_RECEIVE = 'STATUSES_RECEIVE' 3 | export const STATUSES_FAILURE = 'STATUSES_FAILURE' 4 | 5 | export const STATUSES_SELECT = 'STATUSES_SELECT' 6 | export const STATUSES_DESELECT = 'STATUSES_DESELECT' 7 | 8 | export const STATUS_UPDATE_REQUEST = 'STATUS_UPDATE_REQUEST' 9 | export const STATUS_UPDATE_SUCCESS = 'STATUS_UPDATE_SUCCESS' 10 | export const STATUS_UPDATE_FAILURE = 'STATUS_UPDATE_FAILURE' 11 | 12 | export const STATUS_CREATE_SUCCESS = 'STATUS_CREATE_SUCCESS' 13 | export const STATUS_DELETE_SUCCESS = 'STATUS_DELETE_SUCCESS' 14 | -------------------------------------------------------------------------------- /src/admin/client/modules/orderStatuses/edit/components/style.css: -------------------------------------------------------------------------------- 1 | .shortBox { 2 | max-width: 300px; 3 | } 4 | 5 | .button { 6 | margin-left: 12px; 7 | } 8 | 9 | .toggle { 10 | margin-top: 12px; 11 | margin-bottom: 22px; 12 | } 13 | 14 | .innerBox { 15 | padding: 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/orderStatuses/edit/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { reset } from 'redux-form'; 3 | import { updateStatus, createStatus, deselectStatus } from '../actions' 4 | import Form from './components/form' 5 | 6 | const mapStateToProps = (state) => { 7 | return { 8 | statusId: state.orderStatuses.selectedId, 9 | items: state.orderStatuses.items, 10 | initialValues: state.orderStatuses.items.find((item) => (item.id === state.orderStatuses.selectedId)), 11 | isSaving: state.orderStatuses.isSaving 12 | } 13 | } 14 | 15 | const mapDispatchToProps = (dispatch) => { 16 | return { 17 | onSubmit: (values) => { 18 | if(values.id) { 19 | dispatch(updateStatus(values)); 20 | } else { 21 | dispatch(createStatus(values)); 22 | } 23 | }, 24 | onCancel: () => { 25 | dispatch(deselectStatus()); 26 | dispatch(reset('FormOrderStatus')); 27 | } 28 | } 29 | } 30 | 31 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 32 | -------------------------------------------------------------------------------- /src/admin/client/modules/orderStatuses/head/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { reset } from 'redux-form'; 4 | import { deleteStatus, deselectStatus } from '../actions' 5 | import Buttons from './components/buttons' 6 | 7 | const mapStateToProps = (state) => { 8 | return { 9 | selected: state.orderStatuses.items.find(item => item.id === state.orderStatuses.selectedId) 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch) => { 14 | return { 15 | onDelete: (id) => { 16 | dispatch(deleteStatus(id)); 17 | dispatch(reset('FormOrderStatus')); 18 | }, 19 | onCreate: () => { 20 | dispatch(deselectStatus()) 21 | } 22 | } 23 | } 24 | 25 | export default connect(mapStateToProps, mapDispatchToProps)(Buttons); 26 | -------------------------------------------------------------------------------- /src/admin/client/modules/orderStatuses/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { selectStatus, fetchStatusesIfNeeded } from '../actions' 3 | import { fetchOrders } from '../../orders/actions' 4 | import List from '../components/list' 5 | 6 | const mapStateToProps = (state) => { 7 | return { 8 | items: state.orderStatuses.items, 9 | selectedId: state.orderStatuses.selectedId 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch) => { 14 | return { 15 | onLoad: () => { 16 | dispatch(fetchStatusesIfNeeded()); 17 | }, 18 | onSelect: (statusId) => { 19 | dispatch(selectStatus(statusId)); 20 | dispatch(fetchOrders()); 21 | } 22 | } 23 | } 24 | 25 | export default connect(mapStateToProps, mapDispatchToProps)(List); 26 | -------------------------------------------------------------------------------- /src/admin/client/modules/orderStatuses/select/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchStatusesIfNeeded } from '../actions' 3 | import List from '../components/list' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | items: state.orderStatuses.items 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchStatusesIfNeeded()); 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(List); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/orders/editHead/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { withRouter } from 'react-router' 4 | import { addOrderItem, updateOrder, deleteCurrentOrder, closeOrder, cancelOrder } from '../actions' 5 | import Buttons from './components/buttons' 6 | 7 | const mapStateToProps = (state, ownProps) => { 8 | return { 9 | settings: state.settings.settings, 10 | order: state.orders.editOrder 11 | } 12 | } 13 | 14 | const mapDispatchToProps = (dispatch, ownProps) => { 15 | return { 16 | onDelete: () => { 17 | dispatch(deleteCurrentOrder()); 18 | ownProps.history.push('/admin/orders'); 19 | }, 20 | setCancelled: (orderId) => { 21 | dispatch(cancelOrder(orderId)); 22 | }, 23 | holdOrder: (orderId) => { 24 | dispatch(updateOrder({ id: orderId, hold: true })); 25 | }, 26 | resumeOrder: (orderId) => { 27 | dispatch(updateOrder({ id: orderId, hold: false })); 28 | }, 29 | setClosed: (orderId) => { 30 | dispatch(closeOrder(orderId)); 31 | }, 32 | addItem: (orderId, productId) => { 33 | dispatch(addOrderItem(orderId, productId)); 34 | } 35 | } 36 | } 37 | 38 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 39 | -------------------------------------------------------------------------------- /src/admin/client/modules/orders/list/components/head.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Subheader from 'material-ui/Subheader'; 3 | import Checkbox from 'material-ui/Checkbox'; 4 | import messages from 'lib/text' 5 | 6 | export default ({ onSelectAll }) => ( 7 | 8 |
9 |
10 | { onSelectAll(isInputChecked); }} /> 11 |
12 |
13 |
14 |
15 | {messages.order} 16 |
17 |
18 | {messages.orders_shippingTo} 19 |
20 |
21 | {messages.orders_total} 22 |
23 |
24 | {messages.orders_status} 25 |
26 |
27 |
28 | ) 29 | -------------------------------------------------------------------------------- /src/admin/client/modules/orders/list/components/style.css: -------------------------------------------------------------------------------- 1 | .number { 2 | text-decoration: none; 3 | font-weight: 400; 4 | color: rgb(0,142,180); 5 | } 6 | 7 | .small { 8 | color: rgba(0, 0, 0, 0.4); 9 | } 10 | 11 | .price { 12 | word-break: break-all; 13 | text-align: right; 14 | } 15 | 16 | .shipping { 17 | font-size: 14px; 18 | } 19 | 20 | .status { 21 | text-align: right; 22 | font-size: 14px; 23 | } 24 | 25 | .more { 26 | padding: 40px 0; 27 | text-align: center; 28 | } 29 | -------------------------------------------------------------------------------- /src/admin/client/modules/orders/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { fetchOrders, selectOrder, deselectOrder, selectAllOrder, deselectAllOrder, fetchMoreOrders } from '../actions' 4 | import List from './components/list' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | settings: state.settings.settings, 9 | items: state.orders.items, 10 | selected: state.orders.selected, 11 | loadingItems: state.orders.loadingItems, 12 | hasMore: state.orders.hasMore 13 | } 14 | } 15 | 16 | const mapDispatchToProps = (dispatch, ownProps) => { 17 | return { 18 | onLoad: () => { 19 | dispatch(fetchOrders()); 20 | }, 21 | onSelect: (orderId, checked) => { 22 | if(checked) { 23 | dispatch(selectOrder(orderId)); 24 | } else { 25 | dispatch(deselectOrder(orderId)); 26 | } 27 | }, 28 | onSelectAll: (checked) => { 29 | if(checked) { 30 | dispatch(selectAllOrder()); 31 | } else { 32 | dispatch(deselectAllOrder()); 33 | } 34 | }, 35 | loadMore: () => { 36 | dispatch(fetchMoreOrders()); 37 | } 38 | } 39 | } 40 | 41 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(List)); 42 | -------------------------------------------------------------------------------- /src/admin/client/modules/orders/listFilter/components/style.css: -------------------------------------------------------------------------------- 1 | .filter { 2 | padding: 0 16px; 3 | } 4 | 5 | .select {} 6 | -------------------------------------------------------------------------------- /src/admin/client/modules/orders/listHead/components/search.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import messages from 'lib/text' 3 | import TextField from 'material-ui/TextField'; 4 | 5 | export default ({ value, setSearch }) => { 6 | return ( 7 | { setSearch(v); }} 10 | hintText={messages.orders_search} 11 | underlineShow={false} 12 | style={{ float: 'left', marginRight: 10 }} 13 | hintStyle={{ color: 'rgba(255,255,255,0.4)', textIndent: '16px' }} 14 | inputStyle={{ color:'#fff', backgroundColor: 'rgba(255,255,255,0.2)', borderRadius: '4px', textIndent: '16px' }} 15 | /> 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/orders/listHead/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { withRouter } from 'react-router' 4 | import { fetchOrders, setFilter, deleteOrders, createOrder } from '../actions' 5 | import Buttons from './components/buttons' 6 | 7 | const mapStateToProps = (state, ownProps) => { 8 | return { 9 | search: state.orders.filter.search, 10 | selectedCount: state.orders.selected.length 11 | } 12 | } 13 | 14 | const mapDispatchToProps = (dispatch, ownProps) => { 15 | return { 16 | setSearch: (value) => { 17 | dispatch(setFilter({ search: value })); 18 | dispatch(fetchOrders()); 19 | }, 20 | onDelete: () => { 21 | dispatch(deleteOrders()); 22 | }, 23 | onCreate: () => { 24 | dispatch(createOrder(ownProps.history)) 25 | } 26 | } 27 | } 28 | 29 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 30 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const PAGES_REQUEST = 'PAGES_REQUEST' 2 | export const PAGES_RECEIVE = 'PAGES_RECEIVE' 3 | 4 | export const PAGE_REQUEST = 'PAGE_REQUEST' 5 | export const PAGE_RECEIVE = 'PAGE_RECEIVE' 6 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/edit/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/edit/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { deletePage } from '../actions' 4 | import Buttons from './components/headButtons' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | page: state.pages.pageEdit 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch, ownProps) => { 13 | return { 14 | onDelete: (id) => { 15 | dispatch(deletePage(id)); 16 | ownProps.history.push('/admin/pages'); 17 | } 18 | } 19 | } 20 | 21 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 22 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/edit/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchPage, updatePage, createPage, receivePage } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | const {pageId} = ownProps.match.params; 7 | return { 8 | pageId: pageId, 9 | initialValues: state.pages.pageEdit 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch, ownProps) => { 14 | return { 15 | onLoad: () => { 16 | const {pageId} = ownProps.match.params; 17 | if(pageId) { 18 | dispatch(fetchPage(pageId)) 19 | } else { 20 | dispatch(receivePage({ enabled: true })); 21 | } 22 | }, 23 | onSubmit: (page) => { 24 | if(page.id) { 25 | dispatch(updatePage(page)); 26 | } else { 27 | dispatch(createPage(page)); 28 | ownProps.history.push('/admin/pages'); 29 | } 30 | }, 31 | eraseData: () => { 32 | dispatch(receivePage(null)); 33 | } 34 | } 35 | } 36 | 37 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 38 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/list/components/headButtons.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import messages from 'lib/text' 4 | import FontIcon from 'material-ui/FontIcon' 5 | import IconButton from 'material-ui/IconButton' 6 | 7 | const Buttons = () => ( 8 | 9 | 10 | 11 | add 12 | 13 | 14 | 15 | ) 16 | 17 | export default Buttons; 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/list/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import Buttons from './components/headButtons' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return {} 7 | } 8 | 9 | const mapDispatchToProps = (dispatch, ownProps) => { 10 | return {} 11 | } 12 | 13 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 14 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchPages } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | pages: state.pages.pages 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchPages()) 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/pages/reducer.js: -------------------------------------------------------------------------------- 1 | import * as t from './actionTypes' 2 | 3 | const initialState = { 4 | pages: [], 5 | pageEdit: null 6 | }; 7 | 8 | export default(state = initialState, action) => { 9 | switch (action.type) { 10 | case t.PAGES_RECEIVE: 11 | return Object.assign({}, state, {pages: action.pages}) 12 | case t.PAGE_RECEIVE: 13 | return Object.assign({}, state, {pageEdit: action.pageEdit}) 14 | default: 15 | return state 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/productCategories/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const CATEGORIES_REQUEST = 'CATEGORIES_REQUEST' 2 | export const CATEGORIES_RECEIVE = 'CATEGORIES_RECEIVE' 3 | export const CATEGORIES_FAILURE = 'CATEGORIES_FAILURE' 4 | 5 | export const CATEGORIES_SELECT = 'CATEGORIES_SELECT' 6 | export const CATEGORIES_DESELECT = 'CATEGORIES_DESELECT' 7 | 8 | export const CATEGORY_UPDATE_REQUEST = 'CATEGORY_UPDATE_REQUEST' 9 | export const CATEGORY_UPDATE_SUCCESS = 'CATEGORY_UPDATE_SUCCESS' 10 | export const CATEGORY_UPDATE_FAILURE = 'CATEGORY_UPDATE_FAILURE' 11 | 12 | export const CATEGORY_CREATE_SUCCESS = 'CATEGORY_CREATE_SUCCESS' 13 | export const CATEGORY_DELETE_SUCCESS = 'CATEGORY_DELETE_SUCCESS' 14 | export const CATEGORY_MOVE_UPDOWN_SUCCESS = 'CATEGORY_MOVE_UPDOWN_SUCCESS' 15 | export const CATEGORY_REPLACE_SUCCESS = 'CATEGORY_REPLACE_SUCCESS' 16 | 17 | export const CATEGORY_IMAGE_UPLOAD_START = 'CATEGORY_IMAGE_UPLOAD_START' 18 | export const CATEGORY_IMAGE_UPLOAD_END = 'CATEGORY_IMAGE_UPLOAD_END' 19 | -------------------------------------------------------------------------------- /src/admin/client/modules/productCategories/edit/components/style.css: -------------------------------------------------------------------------------- 1 | .shortBox { 2 | max-width: 300px; 3 | } 4 | 5 | .button { 6 | margin-left: 12px; 7 | } 8 | 9 | .toggle { 10 | margin-top: 12px; 11 | margin-bottom: 22px; 12 | } 13 | 14 | .innerBox { 15 | padding: 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/productCategories/edit/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { updateCategory, deselectCategory, fetchCategories, deleteImage, uploadImage } from '../actions' 3 | import ProductCategoryEditForm from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | uploadingImage: state.productCategories.uploadingImage, 8 | categoryId: state.productCategories.selectedId, 9 | items: state.productCategories.items, 10 | initialValues: state.productCategories.items.find((item) => (item.id === state.productCategories.selectedId)), 11 | isSaving: state.productCategories.isSaving 12 | } 13 | } 14 | 15 | const mapDispatchToProps = (dispatch) => { 16 | return { 17 | onImageDelete: () => { 18 | dispatch(deleteImage()); 19 | }, 20 | onImageUpload: (form) => { 21 | dispatch(uploadImage(form)); 22 | }, 23 | onSubmit: (values) => { 24 | delete values.image; 25 | if(!values.slug || values.slug === '') { 26 | values.slug = values.name; 27 | } 28 | dispatch(updateCategory(values)); 29 | } 30 | } 31 | } 32 | 33 | export default connect(mapStateToProps, mapDispatchToProps)(ProductCategoryEditForm); 34 | -------------------------------------------------------------------------------- /src/admin/client/modules/productCategories/head/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { withRouter } from 'react-router' 4 | import { reset } from 'redux-form'; 5 | import { deleteCategory, moveUpCategory, moveDownCategory, replaceCategory, createCategory } from '../actions' 6 | import Buttons from './components/buttons' 7 | 8 | const mapStateToProps = (state) => { 9 | return { 10 | selected: state.productCategories.items.find((item) => (item.id === state.productCategories.selectedId)) 11 | } 12 | } 13 | 14 | const mapDispatchToProps = (dispatch) => { 15 | return { 16 | onMoveUp: () => { 17 | dispatch(moveUpCategory()); 18 | }, 19 | onMoveDown: () => { 20 | dispatch(moveDownCategory()); 21 | }, 22 | onDelete: (id) => { 23 | dispatch(deleteCategory(id)); 24 | dispatch(reset('FormProductCategory')); 25 | }, 26 | onMoveTo: (id) => { 27 | dispatch(replaceCategory(id)); 28 | dispatch(reset('FormProductCategory')); 29 | }, 30 | onCreate: () => { 31 | dispatch(createCategory()); 32 | } 33 | } 34 | } 35 | 36 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 37 | -------------------------------------------------------------------------------- /src/admin/client/modules/productCategories/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { selectCategory, fetchCategoriesIfNeeded } from '../actions' 3 | import { fetchProducts } from '../../products/actions' 4 | import List from '../components/list' 5 | 6 | const mapStateToProps = (state) => { 7 | return { 8 | items: state.productCategories.items, 9 | selectedId: state.productCategories.selectedId 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch) => { 14 | return { 15 | onLoad: () => { 16 | dispatch(fetchCategoriesIfNeeded()); 17 | }, 18 | onSelect: (categoryId) => { 19 | dispatch(selectCategory(categoryId)); 20 | dispatch(fetchProducts()); 21 | }, 22 | onCreate: () => { 23 | dispatch(createCategory()) 24 | } 25 | } 26 | } 27 | 28 | export default connect(mapStateToProps, mapDispatchToProps)(List); 29 | -------------------------------------------------------------------------------- /src/admin/client/modules/productCategories/select/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { selectCategory, fetchCategoriesIfNeeded, createCategory } from '../actions' 3 | import List from '../components/list' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | items: state.productCategories.items 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchCategoriesIfNeeded()); 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(List); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/additional/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { updateProduct } from '../../actions' 4 | import ProductAdditionalForm from './components/form' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | initialValues: state.products.editProduct, 9 | settings: state.settings.settings 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch, ownProps) => { 14 | return { 15 | onSubmit: (values) => { 16 | dispatch(updateProduct({ 17 | id: values.id, 18 | tags: values.tags, 19 | related_product_ids: values.related_product_ids 20 | })); 21 | } 22 | } 23 | } 24 | 25 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ProductAdditionalForm)); 26 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/attributes/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .childrenBox { 10 | padding: 0 30px 30px 30px; 11 | } 12 | 13 | .error { 14 | color: rgb(244, 67, 54); 15 | } 16 | 17 | .head { 18 | background-color: rgba(0, 0, 0, 0.05); 19 | color: #a1a1a1; 20 | padding: 18px 0 18px 30px !important; 21 | } 22 | 23 | .input { 24 | width: 100%; 25 | margin: 0; 26 | padding: 0; 27 | border: none; 28 | outline: none; 29 | background-color: transparent; 30 | font-size: 15px; 31 | height: 60px; 32 | text-indent: 30px; 33 | } 34 | 35 | .input:hover, 36 | .input:focus { 37 | background-color: rgba(0, 0, 0, 0.05); 38 | } 39 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/attributes/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { updateProduct } from '../../actions' 4 | import ProductAttributesForm from './components/form' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | initialValues: state.products.editProduct 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch, ownProps) => { 13 | return { 14 | onSubmit: (values) => { 15 | dispatch(updateProduct({ 16 | id: values.id, 17 | attributes: values.attributes 18 | })); 19 | } 20 | } 21 | } 22 | 23 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ProductAttributesForm)); 24 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/general/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px 30px 50px 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/general/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { updateProduct } from '../../actions' 4 | import ProductGeneralForm from './components/form' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | initialValues: state.products.editProduct 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch, ownProps) => { 13 | return { 14 | onSubmit: (values) => { 15 | dispatch(updateProduct({ 16 | id: values.id, 17 | name: values.name, 18 | slug: values.slug, 19 | meta_title: values.meta_title, 20 | meta_description: values.meta_description, 21 | description: values.description 22 | })); 23 | } 24 | } 25 | } 26 | 27 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ProductGeneralForm)); 28 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/images/components/images.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Gallery from 'modules/shared/imageUploadMultiple' 3 | import Paper from 'material-ui/Paper'; 4 | 5 | export default class ProductImages extends React.Component { 6 | constructor(props) { 7 | super(props); 8 | } 9 | 10 | componentDidMount() { 11 | this.props.fetchData(); 12 | } 13 | 14 | render() { 15 | let {productId, images, onImageDelete, onImageSort, onImageUpload, uploadingImages} = this.props; 16 | return ( 17 | 18 |
19 | 20 |
21 |
22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/inventory/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/inventory/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { updateProduct } from '../../actions' 4 | import ProductInventoryForm from './components/form' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | settings: state.settings.settings, 9 | initialValues: state.products.editProduct 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch, ownProps) => { 14 | return { 15 | onSubmit: (values) => { 16 | dispatch(updateProduct({ 17 | id: values.id, 18 | regular_price: values.regular_price, 19 | sale_price: values.sale_price, 20 | date_sale_from: values.date_sale_from, 21 | date_sale_to: values.date_sale_to, 22 | sku: values.sku, 23 | stock_quantity: values.stock_quantity, 24 | weight: values.weight, 25 | date_stock_expected: values.date_stock_expected, 26 | stock_tracking: values.stock_tracking, 27 | stock_preorder: values.stock_preorder, 28 | stock_backorder: values.stock_backorder, 29 | discontinued: values.discontinued, 30 | enabled: values.enabled 31 | })); 32 | } 33 | } 34 | } 35 | 36 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ProductInventoryForm)); 37 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/option/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | 13 | .shortControl { 14 | max-width: 300px; 15 | margin: 15px 0; 16 | } 17 | 18 | .grid {} 19 | 20 | .gridRow { 21 | display: flex; 22 | flex-flow: row wrap; 23 | width: 100%; 24 | align-items: center; 25 | justify-content: space-around; 26 | align-items: center; 27 | border-top: 1px solid rgb(224, 224, 224); 28 | } 29 | 30 | .gridRow:hover { 31 | background-color: rgba(0, 0, 0, 0.03); 32 | } 33 | 34 | .gridColInput { 35 | padding-left: 30px; 36 | flex: 8 1; 37 | } 38 | .gridColButton { 39 | padding-right: 30px; 40 | text-align: right; 41 | flex: 1 1; 42 | } 43 | 44 | .textInput { 45 | width: 100%; 46 | margin: 0; 47 | padding: 0; 48 | border: none; 49 | outline: none; 50 | background-color: transparent; 51 | font-size: 15px; 52 | height: 60px; 53 | } 54 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/edit/variants/components/style.css: -------------------------------------------------------------------------------- 1 | .innerBox { 2 | padding: 30px; 3 | } 4 | 5 | .grid {} 6 | 7 | .gridHeadRow{ 8 | display: flex; 9 | flex-flow: row wrap; 10 | width: 100%; 11 | background-color: rgba(0, 0, 0, 0.05); 12 | color: #a1a1a1; 13 | align-items: center; 14 | justify-content: space-around; 15 | align-items: center; 16 | text-align: center; 17 | min-height: 60px; 18 | cursor: default; 19 | } 20 | 21 | .gridHeadRow a { 22 | color: #000; 23 | text-decoration: none; 24 | cursor: pointer; 25 | } 26 | 27 | .gridRow { 28 | display: flex; 29 | flex-flow: row wrap; 30 | width: 100%; 31 | align-items: center; 32 | justify-content: space-around; 33 | align-items: center; 34 | text-align: center; 35 | border-bottom: 1px solid rgb(224, 224, 224); 36 | } 37 | 38 | .gridCol { 39 | flex: 1 1; 40 | overflow: hidden; 41 | } 42 | 43 | .gridCol:hover, 44 | .textInput:focus { 45 | background-color: rgba(0, 0, 0, 0.05); 46 | } 47 | 48 | .textInput { 49 | width: 100%; 50 | margin: 0; 51 | padding: 0; 52 | border: none; 53 | outline: none; 54 | background-color: transparent; 55 | font-size: 15px; 56 | text-align: center; 57 | height: 60px; 58 | } 59 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/editHead/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { withRouter } from 'react-router' 4 | import { deleteCurrentProduct } from '../actions' 5 | import Buttons from './components/buttons' 6 | 7 | const mapStateToProps = (state, ownProps) => { 8 | return { 9 | product: state.products.editProduct 10 | } 11 | } 12 | 13 | const mapDispatchToProps = (dispatch, ownProps) => { 14 | return { 15 | onDelete: () => { 16 | dispatch(deleteCurrentProduct()); 17 | ownProps.history.push('/admin/products'); 18 | } 19 | } 20 | } 21 | 22 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 23 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/list/components/head.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Subheader from 'material-ui/Subheader'; 3 | import messages from 'lib/text' 4 | 5 | const Head = ({ onSelectAll }) => ( 6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 |
14 | {messages.products_name} 15 |
16 |
17 |
18 |
19 | {messages.products_sku} 20 |
21 |
22 | {messages.products_stock} 23 |
24 |
25 | {messages.products_price} 26 |
27 |
28 |
29 | ) 30 | 31 | export default Head 32 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/list/components/style.css: -------------------------------------------------------------------------------- 1 | .imageBox { 2 | height: 80px; 3 | } 4 | 5 | .image { 6 | max-width: 80px; 7 | max-height: 70px; 8 | border: 1px solid #eee; 9 | } 10 | 11 | .productName { 12 | display: block; 13 | text-decoration: none; 14 | font-weight: 400; 15 | font-size: 14px; 16 | } 17 | 18 | .productName small { 19 | color: rgba(0, 0, 0, 0.4); 20 | } 21 | 22 | .productActive { 23 | color: rgb(0,142,180); 24 | } 25 | 26 | .productInactive { 27 | color: rgba(0, 0, 0, 0.3); 28 | } 29 | 30 | .sku { 31 | word-break: break-all; 32 | } 33 | 34 | .stock { 35 | word-break: break-all; 36 | } 37 | 38 | .inStock { 39 | color: rgb(122,179,23); 40 | } 41 | 42 | .outOfStock { 43 | color: rgb(228,86,53); 44 | } 45 | 46 | .backorder { 47 | color: rgb(251,184,41); 48 | } 49 | 50 | .preorder { 51 | /*color: rgb(228,86,53);*/ 52 | } 53 | 54 | .discontinued { 55 | color: rgba(0, 0, 0, 0.3); 56 | } 57 | 58 | .price { 59 | word-break: break-all; 60 | text-align: right;; 61 | } 62 | 63 | .price small { 64 | display: block; 65 | text-decoration: line-through; 66 | color: rgba(0, 0, 0, 0.4); 67 | } 68 | 69 | .more { 70 | padding: 40px 0; 71 | text-align: center; 72 | } 73 | 74 | .innerItem { 75 | padding: 0 16px; 76 | } 77 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/listFilter/components/style.css: -------------------------------------------------------------------------------- 1 | .filter { 2 | padding: 0 16px; 3 | } 4 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/listFilter/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchProducts, setFilter } from '../actions' 3 | import Filter from './components/filter' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | filter: state.products.filter 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | setEnabled: (value) => { 14 | dispatch(setFilter({ enabled: value })); 15 | dispatch(fetchProducts()); 16 | }, 17 | setDiscontinued: (value) => { 18 | dispatch(setFilter({ discontinued: value })); 19 | dispatch(fetchProducts()); 20 | }, 21 | setOnSale: (value) => { 22 | dispatch(setFilter({ onSale: value })); 23 | dispatch(fetchProducts()); 24 | }, 25 | setStock: (value) => { 26 | dispatch(setFilter({ stockStatus: value })); 27 | dispatch(fetchProducts()); 28 | } 29 | } 30 | } 31 | 32 | export default connect(mapStateToProps, mapDispatchToProps)(Filter); 33 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/listHead/components/search.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import messages from 'lib/text' 3 | import TextField from 'material-ui/TextField'; 4 | 5 | export default ({ value, setSearch }) => { 6 | return ( 7 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/products/listHead/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { withRouter } from 'react-router' 4 | import { fetchProducts, deleteProducts, setCategory, setFilter, createProduct } from '../actions' 5 | import Buttons from './components/buttons' 6 | 7 | const mapStateToProps = (state, ownProps) => { 8 | return { 9 | search: state.products.filter.search, 10 | selectedCount: state.products.selected.length 11 | } 12 | } 13 | 14 | const mapDispatchToProps = (dispatch, ownProps) => { 15 | return { 16 | setSearch: (event, value) => { 17 | dispatch(setFilter({ search: value })); 18 | dispatch(fetchProducts()); 19 | }, 20 | onDelete: () => { 21 | dispatch(deleteProducts()); 22 | }, 23 | onMoveTo: (category_id) => { 24 | dispatch(setCategory(category_id)); 25 | }, 26 | onCreate: () => { 27 | dispatch(createProduct(ownProps.history)) 28 | } 29 | } 30 | } 31 | 32 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 33 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/checkout/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchCheckoutFields } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | checkoutFields: state.settings.checkoutFields 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchCheckoutFields()) 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/checkoutFields/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .toggle { 6 | margin-top: 12px; 7 | margin-bottom: 22px; 8 | } 9 | 10 | .innerBox { 11 | padding: 30px; 12 | } 13 | 14 | .childrenBox { 15 | padding: 0 30px 30px 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/checkoutFields/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchCheckoutField, updateCheckoutField } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return { 7 | initialValues: state.settings.checkoutField 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch, ownProps) => { 12 | return { 13 | onLoad: () => { 14 | const {fieldName} = ownProps.match.params; 15 | dispatch(fetchCheckoutField(fieldName)) 16 | }, 17 | onSubmit: (values) => { 18 | dispatch(updateCheckoutField(values)); 19 | ownProps.history.push('/admin/settings/checkout'); 20 | } 21 | } 22 | } 23 | 24 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 25 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/email/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchEmailSettings } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | emailSettings: state.settings.emailSettings 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchEmailSettings()) 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/emailTemplates/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .toggle { 6 | margin-top: 12px; 7 | margin-bottom: 22px; 8 | } 9 | 10 | .innerBox { 11 | padding: 30px; 12 | } 13 | 14 | .childrenBox { 15 | padding: 0 30px 30px 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/emailTemplates/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchEmailTemplate, updateEmailTemplate } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return { 7 | initialValues: state.settings.emailTemplate 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch, ownProps) => { 12 | return { 13 | onLoad: () => { 14 | const {templateName} = ownProps.match.params; 15 | dispatch(fetchEmailTemplate(templateName)) 16 | }, 17 | onSubmit: (values) => { 18 | dispatch(updateEmailTemplate(values)); 19 | } 20 | } 21 | } 22 | 23 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 24 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/general/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .toggle { 6 | margin-top: 12px; 7 | margin-bottom: 22px; 8 | } 9 | 10 | .innerBox { 11 | padding: 30px; 12 | } 13 | 14 | .childrenBox { 15 | padding: 0 30px 30px 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/general/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchSettings, updateSettings } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | initialValues: state.settings.settings 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchSettings()) 15 | }, 16 | onSubmit: (values) => { 17 | dispatch(updateSettings(values)); 18 | } 19 | } 20 | } 21 | 22 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 23 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/generalLogo/components/form.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ImageUpload from 'modules/shared/imageUpload' 3 | import Paper from 'material-ui/Paper'; 4 | 5 | export default class GeneralLogoSettingsForm extends React.Component { 6 | componentDidMount() { 7 | this.props.onLoad(); 8 | } 9 | 10 | render() { 11 | const { onImageUpload, onImageDelete, settings } = this.props; 12 | let imageUrl = settings && settings.logo ? settings.logo : ''; 13 | 14 | return ( 15 | 16 |
17 | 23 |
24 |
25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/generalLogo/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchSettings, deleteLogo, uploadLogo } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | settings: state.settings.settings 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchSettings()) 15 | }, 16 | onImageDelete: () => { 17 | dispatch(deleteLogo()); 18 | }, 19 | onImageUpload: (form) => { 20 | dispatch(uploadLogo(form)); 21 | } 22 | } 23 | } 24 | 25 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 26 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/paymentGateway/availablePaymentGateways.js: -------------------------------------------------------------------------------- 1 | export const AVAILABLE_PAYMENT_GATEWAYS = [ 2 | { 3 | 'key': 'paypal-checkout', 4 | 'name': 'PayPal Express Checkout' 5 | }, 6 | { 7 | 'key': 'liqpay', 8 | 'name': 'LiqPay' 9 | } 10 | ]; 11 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/paymentGateway/components/style.css: -------------------------------------------------------------------------------- 1 | .buttons{ 2 | text-align: right; 3 | margin-top: 20px; 4 | } 5 | 6 | .error { 7 | color: rgb(244, 67, 54); 8 | } 9 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/paymentGateway/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchPaymentGateway, updatePaymentGateway } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return { 7 | gateway: ownProps.gateway, 8 | initialValues: state.settings.paymentGatewayEdit 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch, ownProps) => { 13 | return { 14 | onLoad: (gateway) => { 15 | dispatch(fetchPaymentGateway(gateway || ownProps.gateway)); 16 | }, 17 | onSubmit: (data) => { 18 | dispatch(updatePaymentGateway(ownProps.gateway, data)); 19 | } 20 | } 21 | } 22 | 23 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 24 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/payments/components/headButtons.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import messages from 'lib/text' 4 | import FontIcon from 'material-ui/FontIcon' 5 | import IconButton from 'material-ui/IconButton' 6 | 7 | const Buttons = () => ( 8 | 9 | 10 | 11 | add 12 | 13 | 14 | 15 | ) 16 | 17 | export default Buttons; 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/payments/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import Buttons from './components/headButtons' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return {} 7 | } 8 | 9 | const mapDispatchToProps = (dispatch, ownProps) => { 10 | return {} 11 | } 12 | 13 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 14 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/payments/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchPaymentMethods } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | paymentMethods: state.settings.paymentMethods 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchPaymentMethods()) 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/paymentsEdit/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/paymentsEdit/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { deletePaymentMethod } from '../actions' 4 | import Buttons from './components/headButtons' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | paymentMethod: state.settings.paymentMethodEdit 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch, ownProps) => { 13 | return { 14 | onDelete: (id) => { 15 | dispatch(deletePaymentMethod(id)); 16 | ownProps.history.push('/admin/settings/payments'); 17 | } 18 | } 19 | } 20 | 21 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 22 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/shipping/components/headButtons.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import messages from 'lib/text' 4 | import FontIcon from 'material-ui/FontIcon' 5 | import IconButton from 'material-ui/IconButton' 6 | 7 | const Buttons = () => ( 8 | 9 | 10 | 11 | add 12 | 13 | 14 | 15 | ) 16 | 17 | export default Buttons; 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/shipping/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import Buttons from './components/headButtons' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return {} 7 | } 8 | 9 | const mapDispatchToProps = (dispatch, ownProps) => { 10 | return {} 11 | } 12 | 13 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 14 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/shipping/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchShippingMethods } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | shippingMethods: state.settings.shippingMethods 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchShippingMethods()) 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/shippingEdit/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/shippingEdit/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import { deleteShippingMethod } from '../actions' 4 | import Buttons from './components/headButtons' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | shippingMethod: state.settings.shippingMethodEdit 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch, ownProps) => { 13 | return { 14 | onDelete: (id) => { 15 | dispatch(deleteShippingMethod(id)); 16 | ownProps.history.push('/admin/settings/shipping'); 17 | } 18 | } 19 | } 20 | 21 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 22 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/smtp/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/smtp/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchEmailSettings, updateEmailSettings } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | initialValues: state.settings.emailSettings 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchEmailSettings()) 15 | }, 16 | onSubmit: (values) => { 17 | dispatch(updateEmailSettings(values)); 18 | } 19 | } 20 | } 21 | 22 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 23 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/theme/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .toggle { 6 | margin-top: 12px; 7 | margin-bottom: 22px; 8 | } 9 | 10 | .innerBox { 11 | padding: 30px; 12 | } 13 | 14 | .childrenBox { 15 | padding: 0 30px 30px 30px; 16 | } 17 | 18 | .error { 19 | color: rgb(244, 67, 54); 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/theme/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { exportRequest, exportReceive, installRequest, installReceive } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | exportInProcess: state.settings.exportInProcess, 8 | installInProcess: state.settings.installInProcess 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch) => { 13 | return { 14 | exportRequest: () => { 15 | dispatch(exportRequest()); 16 | }, 17 | exportReceive: () => { 18 | dispatch(exportReceive()); 19 | }, 20 | installRequest: () => { 21 | dispatch(installRequest()); 22 | }, 23 | installReceive: () => { 24 | dispatch(installReceive()) 25 | } 26 | } 27 | } 28 | 29 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 30 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/themeSettings/components/imageEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import api from 'lib/api' 3 | import ImageUpload from 'modules/shared/imageUpload' 4 | 5 | export default class ThemeImageUpload extends React.Component { 6 | constructor(props) { 7 | super(props); 8 | } 9 | 10 | onDelete = () => { 11 | const fileName = this.props.input.value; 12 | api.theme.assets.deleteFile(fileName).then(() => { 13 | this.props.input.onChange(''); 14 | }) 15 | } 16 | 17 | onUpload = formData => { 18 | api.theme.assets.uploadFile(formData).then(({ status, json }) => { 19 | const fileName = json.file; 20 | this.props.input.onChange(fileName); 21 | }); 22 | } 23 | 24 | render() { 25 | let { input, label } = this.props; 26 | const imageUrl = input.value && input.value.length > 0 ? '/assets/images/' + input.value : null; 27 | 28 | return ( 29 |
30 |

{label}

31 | 37 |
38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/themeSettings/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .arrayInnerBox { 10 | padding: 0 30px 20px 30px; 11 | } 12 | 13 | .arrayTitle{ 14 | margin: 40px 0 0 0; 15 | display: flex; 16 | align-items: center; 17 | } 18 | 19 | .arrayItemHead { 20 | padding: 4px; 21 | } 22 | 23 | .colorInput { 24 | padding-top: 16px; 25 | padding-bottom: 16px; 26 | } 27 | 28 | .colorInput label { 29 | margin-right: 20px; 30 | } 31 | 32 | .sectionTitle { 33 | font-size: 24px; 34 | font-weight: 400; 35 | margin: 40px -30px 0px -30px; 36 | padding: 15px 30px; 37 | background-color: #f1f1f1; 38 | } 39 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/themeSettings/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchThemeSettings, updateThemeSettings } from '../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | initialValues: state.settings.themeSettings, 8 | settingsSchema: state.settings.themeSettingsSchema 9 | } 10 | } 11 | 12 | const mapDispatchToProps = (dispatch) => { 13 | return { 14 | onLoad: () => { 15 | dispatch(fetchThemeSettings()) 16 | }, 17 | onSubmit: (values) => { 18 | dispatch(updateThemeSettings(values)); 19 | } 20 | } 21 | } 22 | 23 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 24 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/tokens/edit/components/style.css: -------------------------------------------------------------------------------- 1 | .button { 2 | margin-left: 12px; 3 | } 4 | 5 | .innerBox { 6 | padding: 30px; 7 | } 8 | 9 | .error { 10 | color: rgb(244, 67, 54); 11 | } 12 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/tokens/edit/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchToken, updateToken, createToken, receiveToken, deleteToken } from '../../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | const {tokenId} = ownProps.match.params; 7 | return { 8 | tokenId: tokenId, 9 | initialValues: state.settings.tokenEdit, 10 | newToken: state.settings.newToken 11 | } 12 | } 13 | 14 | const mapDispatchToProps = (dispatch, ownProps) => { 15 | return { 16 | onLoad: () => { 17 | const {tokenId} = ownProps.match.params; 18 | if(tokenId) { 19 | dispatch(fetchToken(tokenId)) 20 | } else { 21 | dispatch(receiveToken({ expiration: 24 })); 22 | } 23 | }, 24 | onSubmit: (token) => { 25 | if(token.id) { 26 | dispatch(updateToken(token)); 27 | } else { 28 | dispatch(createToken(token)); 29 | } 30 | }, 31 | onDelete: () => { 32 | const {tokenId} = ownProps.match.params; 33 | dispatch(deleteToken(tokenId)); 34 | ownProps.history.push('/admin/settings/tokens'); 35 | } 36 | } 37 | } 38 | 39 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 40 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/tokens/list/components/headButtons.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import messages from 'lib/text' 4 | import FontIcon from 'material-ui/FontIcon' 5 | import IconButton from 'material-ui/IconButton' 6 | 7 | const Buttons = () => ( 8 | 9 | 10 | 11 | add 12 | 13 | 14 | 15 | ) 16 | 17 | export default Buttons; 18 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/tokens/list/head.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { withRouter } from 'react-router' 3 | import Buttons from './components/headButtons' 4 | 5 | const mapStateToProps = (state, ownProps) => { 6 | return {} 7 | } 8 | 9 | const mapDispatchToProps = (dispatch, ownProps) => { 10 | return {} 11 | } 12 | 13 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Buttons)); 14 | -------------------------------------------------------------------------------- /src/admin/client/modules/settings/tokens/list/index.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { fetchTokens } from '../../actions' 3 | import Form from './components/form' 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | tokens: state.settings.tokens 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onLoad: () => { 14 | dispatch(fetchTokens()) 15 | } 16 | } 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(Form); 20 | -------------------------------------------------------------------------------- /src/admin/client/modules/shared/form/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Toggle from 'material-ui/Toggle'; 3 | import TextField from 'material-ui/TextField'; 4 | 5 | export const CustomToggle = ({ input, label, className = '', disabled = false, style }) => { 6 | return ( 7 | { 11 | input.onChange(isInputChecked) 12 | }} 13 | className={className} 14 | disabled={disabled} 15 | style={style} 16 | /> 17 | ) 18 | } 19 | 20 | export const NumberField = ({ input, label, className = '', disabled = false, style }) => ( 21 | { 28 | let number = parseFloat(value); 29 | number = number ? number : 0; 30 | input.onChange(number) 31 | }} 32 | /> 33 | ) 34 | 35 | export const ColorField = ({ input, meta: { touched, error } }) => ( 36 | 37 | ) 38 | -------------------------------------------------------------------------------- /src/admin/client/modules/shared/imageUpload/style.css: -------------------------------------------------------------------------------- 1 | .preview { 2 | height: 220px; 3 | width: 200px; 4 | } 5 | 6 | .preview img { 7 | max-width: 100%; 8 | max-height: 100%; 9 | } 10 | 11 | .footer { 12 | background-color: rgba(0,0,0,0.05); 13 | } 14 | 15 | .dropzone { 16 | cursor: pointer; 17 | } 18 | .dropText { 19 | color: #a1a1a1; 20 | font-size: 14px; 21 | } 22 | .dropzoneActive { 23 | background-color: rgba(18,179,117, 0.4); 24 | } 25 | .dropzoneReject { 26 | background-color: rgba(244,67,54,0.8); 27 | } 28 | .dropzoneReject .preview img, 29 | .dropzoneActive .preview img { 30 | opacity: 0.3 31 | } 32 | 33 | .noImage { 34 | display: flex; 35 | height: 100%; 36 | text-align: center; 37 | align-items: center; 38 | justify-content: center; 39 | flex-direction: column; 40 | } 41 | -------------------------------------------------------------------------------- /src/admin/client/modules/shared/imageUploadMultiple/item.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import messages from 'lib/text' 3 | import style from './style.css' 4 | 5 | import Paper from 'material-ui/Paper'; 6 | import FontIcon from 'material-ui/FontIcon'; 7 | import IconButton from 'material-ui/IconButton'; 8 | 9 | const GalleryItem = ({ url, alt, id, onDelete }) => ( 10 | 11 |
12 | 13 |
14 |
15 | { onDelete(id) }}> 16 | delete 17 | 18 |
19 |
20 | ) 21 | 22 | export default GalleryItem; 23 | -------------------------------------------------------------------------------- /src/admin/client/modules/shared/imageUploadMultiple/style.css: -------------------------------------------------------------------------------- 1 | .preview { 2 | position: relative; 3 | height: 220px; 4 | width: 200px; 5 | cursor: move; 6 | } 7 | 8 | .preview img { 9 | max-width: 100%; 10 | max-height: 100%; 11 | } 12 | 13 | .footer { 14 | background-color: rgba(0,0,0,0.05); 15 | } 16 | 17 | .dropzone {} 18 | .dropzoneEmpty { 19 | color: #a1a1a1; 20 | font-size: 16px; 21 | border: 2px dashed rgba(0,0,0,0.1); 22 | padding: 80px; 23 | margin: 20px 20px 0 20px; 24 | background-color: rgb(255,255,255); 25 | } 26 | .dropzoneActive { 27 | background-color: rgba(18,179,117, 0.4); 28 | } 29 | .dropzoneReject { 30 | background-color: rgba(244,67,54,0.8); 31 | } 32 | .dropzoneReject .list, 33 | .dropzoneActive .list { 34 | opacity: 0.3 35 | } 36 | .gallery { 37 | overflow: auto; 38 | } 39 | 40 | .list { 41 | margin: 10px 10px 0 10px; 42 | padding: 0; 43 | display: flex; 44 | flex-wrap: nowrap; 45 | list-style: none; 46 | } 47 | 48 | .item { 49 | margin: 10px 0px 10px 10px; 50 | padding: 0; 51 | list-style: none; 52 | } 53 | -------------------------------------------------------------------------------- /src/admin/client/modules/shared/tinymce/helpers/ucFirst.js: -------------------------------------------------------------------------------- 1 | export default function ucFirst(str) { 2 | return str[0].toUpperCase() + str.substring(1); 3 | } 4 | -------------------------------------------------------------------------------- /src/admin/client/modules/shared/tinymce/helpers/uuid.js: -------------------------------------------------------------------------------- 1 | let count = 0; 2 | module.exports = function uuid() { 3 | return 'react-tinymce-' + count++; 4 | }; 5 | -------------------------------------------------------------------------------- /src/admin/client/modules/shared/tinymce/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./components/TinyMCE'); 2 | -------------------------------------------------------------------------------- /src/admin/client/rootReducer.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { reducer as formReducer } from 'redux-form' 3 | 4 | import productCategories from 'modules/productCategories/reducer'; 5 | import products from 'modules/products/reducer'; 6 | import customerGroups from 'modules/customerGroups/reducer'; 7 | import customers from 'modules/customers/reducer'; 8 | import orders from 'modules/orders/reducer'; 9 | import orderStatuses from 'modules/orderStatuses/reducer'; 10 | import pages from 'modules/pages/reducer'; 11 | import settings from 'modules/settings/reducer'; 12 | import apps from 'modules/apps/reducer'; 13 | import files from 'modules/files/reducer'; 14 | 15 | export default combineReducers({ 16 | form: formReducer, 17 | productCategories, 18 | products, 19 | settings, 20 | customerGroups, 21 | customers, 22 | orders, 23 | orderStatuses, 24 | pages, 25 | apps, 26 | files 27 | }); 28 | -------------------------------------------------------------------------------- /src/admin/client/routes/apps/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Switch, Route, NavLink } from 'react-router-dom' 3 | import * as auth from 'lib/webstoreAuth' 4 | import NotFound from 'routes/notFound' 5 | import Login from 'routes/apps/login' 6 | import Account from 'modules/apps/account' 7 | import Services from 'modules/apps/services' 8 | import ServiceDetails from 'modules/apps/serviceDetails' 9 | import AppDetails from 'modules/apps/appDetails' 10 | 11 | export default() => ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ) 21 | -------------------------------------------------------------------------------- /src/admin/client/routes/customers/edit.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CustomerDetails from 'modules/customers/edit'; 3 | 4 | export default CustomerDetails; 5 | -------------------------------------------------------------------------------- /src/admin/client/routes/customers/groups/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import GroupEdit from 'modules/customerGroups/edit'; 3 | import Groups from 'modules/customerGroups/list'; 4 | 5 | export default () => ( 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | ) 15 | -------------------------------------------------------------------------------- /src/admin/client/routes/customers/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CustomersList from 'modules/customers/list'; 3 | import Groups from 'modules/customerGroups/list'; 4 | 5 | export default () => ( 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | ) 15 | -------------------------------------------------------------------------------- /src/admin/client/routes/files.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import List from 'modules/files/list'; 3 | 4 | export default () => ( 5 |
6 |
7 | 8 |
9 |
10 | ) 11 | -------------------------------------------------------------------------------- /src/admin/client/routes/home.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default() => ( 4 |
5 |
6 |
7 |
8 |
9 |
10 | ) 11 | -------------------------------------------------------------------------------- /src/admin/client/routes/logout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import * as auth from 'lib/auth' 3 | 4 | export default class Logout extends React.Component { 5 | componentWillMount() { 6 | auth.removeToken(); 7 | } 8 | 9 | render() { 10 | return null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/admin/client/routes/notFound.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import messages from 'lib/text' 3 | 4 | export default() => ( 5 |
6 |
404
7 |
{messages.pageNotFound}
8 |
9 | ) 10 | -------------------------------------------------------------------------------- /src/admin/client/routes/orders/edit.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import OrderDetails from 'modules/orders/edit'; 3 | 4 | export default OrderDetails; 5 | -------------------------------------------------------------------------------- /src/admin/client/routes/orders/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import OrdersList from 'modules/orders/list'; 3 | import OrdersFilter from 'modules/orders/listFilter'; 4 | import Statuses from 'modules/orderStatuses/list'; 5 | 6 | export default () => ( 7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 | ) 17 | -------------------------------------------------------------------------------- /src/admin/client/routes/orders/statuses/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Edit from 'modules/orderStatuses/edit'; 3 | import List from 'modules/orderStatuses/list'; 4 | 5 | export default () => ( 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | ) 15 | -------------------------------------------------------------------------------- /src/admin/client/routes/pages/edit.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route } from 'react-router-dom' 3 | import PageEdit from 'modules/pages/edit' 4 | 5 | const ProductDetails = (props) => { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | 15 | export default ProductDetails; 16 | -------------------------------------------------------------------------------- /src/admin/client/routes/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import List from 'modules/pages/list'; 3 | 4 | export default () => ( 5 |
6 |
7 | 8 |
9 |
10 | ) 11 | -------------------------------------------------------------------------------- /src/admin/client/routes/products/categories/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CategoryEdit from 'modules/productCategories/edit'; 3 | import Categories from 'modules/productCategories/list'; 4 | 5 | export default () => ( 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | ) 15 | -------------------------------------------------------------------------------- /src/admin/client/routes/products/edit.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route } from 'react-router-dom' 3 | import ProductEdit from 'modules/products/edit' 4 | import ProductOption from 'modules/products/edit/option' 5 | 6 | const ProductDetails = (props) => { 7 | return ( 8 |
9 |
10 | 11 | 12 |
13 |
14 | ) 15 | } 16 | 17 | export default ProductDetails; 18 | -------------------------------------------------------------------------------- /src/admin/client/routes/products/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ProductsList from 'modules/products/list'; 3 | import ProductsFilter from 'modules/products/listFilter'; 4 | import Categories from 'modules/productCategories/list'; 5 | 6 | export default () => ( 7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 | ) 17 | -------------------------------------------------------------------------------- /src/api/server/controllers/apps.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | const AppSettingsService = require('../services/apps/settings'); 5 | 6 | class AppsController { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/apps/:key/settings', security.checkUserScope.bind(this, security.scope.READ_SETTINGS), this.getSettings.bind(this)); 14 | this.router.put('/v1/apps/:key/settings', security.checkUserScope.bind(this, security.scope.WRITE_SETTINGS), this.updateSettings.bind(this)); 15 | } 16 | 17 | getSettings(req, res, next) { 18 | AppSettingsService.getSettings(req.params.key).then(data => { 19 | res.send(data) 20 | }).catch(next); 21 | } 22 | 23 | updateSettings(req, res, next) { 24 | AppSettingsService.updateSettings(req.params.key, req.body).then(data => { 25 | if (data) { 26 | res.send(data) 27 | } else { 28 | res.status(404).end() 29 | } 30 | }).catch(next); 31 | } 32 | } 33 | 34 | module.exports = AppsController; 35 | -------------------------------------------------------------------------------- /src/api/server/controllers/data.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var DataService = require('../services/data'); 4 | 5 | class DataController { 6 | constructor(router) { 7 | this.router = router; 8 | this.registerRoutes(); 9 | } 10 | 11 | registerRoutes() { 12 | // this.router.get('/countries', this.getCountries.bind(this)); 13 | // this.router.get('/currencies', this.getCurrencies.bind(this)); 14 | } 15 | 16 | // getCountries(req, res, next) { 17 | // res.send(DataService.getCountries()) 18 | // } 19 | // 20 | // getCurrencies(req, res, next) { 21 | // res.send(DataService.getCurrencies()) 22 | // } 23 | } 24 | 25 | module.exports = DataController; 26 | -------------------------------------------------------------------------------- /src/api/server/controllers/files.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | const FilesService = require('../services/files'); 5 | 6 | class FilesController { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/files', security.checkUserScope.bind(this, security.scope.READ_FILES), this.getFiles.bind(this)); 14 | this.router.post('/v1/files', security.checkUserScope.bind(this, security.scope.WRITE_FILES), this.uploadFile.bind(this)); 15 | this.router.delete('/v1/files/:file', security.checkUserScope.bind(this, security.scope.WRITE_FILES), this.deleteFile.bind(this)); 16 | } 17 | 18 | getFiles(req, res, next) { 19 | FilesService.getFiles() 20 | .then((data) => { 21 | res.send(data) 22 | }) 23 | .catch(next); 24 | } 25 | 26 | uploadFile(req, res, next) { 27 | FilesService.uploadFile(req, res, next); 28 | } 29 | 30 | deleteFile(req, res, next) { 31 | FilesService.deleteFile(req.params.file).then(() => { 32 | res.end() 33 | }).catch(next) 34 | } 35 | } 36 | 37 | module.exports = FilesController; 38 | -------------------------------------------------------------------------------- /src/api/server/controllers/notifications.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const PaymentGateways = require('../paymentGateways'); 4 | 5 | class NotificationsController { 6 | constructor(router) { 7 | this.router = router; 8 | this.registerRoutes(); 9 | } 10 | 11 | registerRoutes() { 12 | this.router.post('/v1/notifications/:gateway', this.paymentNotification.bind(this)); 13 | } 14 | 15 | paymentNotification(req, res, next) { 16 | PaymentGateways.paymentNotification(req, res, req.params.gateway); 17 | } 18 | } 19 | 20 | module.exports = NotificationsController; 21 | -------------------------------------------------------------------------------- /src/api/server/controllers/paymentGateways.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | var PaymentGatewaysService = require('../services/settings/paymentGateways'); 5 | 6 | class PaymentGatewaysController { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/payment_gateways/:name', security.checkUserScope.bind(this, security.scope.READ_PAYMENT_METHODS), this.getGateway.bind(this)); 14 | this.router.put('/v1/payment_gateways/:name', security.checkUserScope.bind(this, security.scope.WRITE_PAYMENT_METHODS), this.updateGateway.bind(this)); 15 | } 16 | 17 | getGateway(req, res, next) { 18 | PaymentGatewaysService.getGateway(req.params.name).then(data => { 19 | res.send(data) 20 | }).catch(next); 21 | } 22 | 23 | updateGateway(req, res, next) { 24 | PaymentGatewaysService.updateGateway(req.params.name, req.body).then(data => { 25 | res.send(data); 26 | }).catch(next); 27 | } 28 | } 29 | 30 | module.exports = PaymentGatewaysController; 31 | -------------------------------------------------------------------------------- /src/api/server/controllers/sitemap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | var SitemapService = require('../services/sitemap'); 5 | 6 | class SitemapController { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/sitemap', security.checkUserScope.bind(this, security.scope.READ_SITEMAP), this.getPaths.bind(this)); 14 | } 15 | 16 | getPaths(req, res, next) { 17 | if (req.query.path) { 18 | SitemapService.getSinglePath(req.query.path, req.query.enabled).then((data) => { 19 | if (data) { 20 | res.send(data) 21 | } else { 22 | res.status(404).end() 23 | } 24 | }).catch(next); 25 | } else { 26 | SitemapService.getPaths(req.query.enabled).then((data) => { 27 | res.send(data) 28 | }).catch(next); 29 | } 30 | } 31 | } 32 | 33 | module.exports = SitemapController; 34 | -------------------------------------------------------------------------------- /src/api/server/lib/events.js: -------------------------------------------------------------------------------- 1 | const security = require('./security.js'); 2 | const settings = require('./settings.js'); 3 | 4 | let subscribers = []; 5 | 6 | const THEME_INSTALLED = 'theme-installed'; 7 | const ORDER_RECEIVED = 'order-received'; 8 | const ORDER_CHANGED = 'order-changed'; 9 | 10 | const subscribe = (req, res) => { 11 | security.verifyToken(req.query.token, settings.jwtSecretKey).then(err => { 12 | if(err){ 13 | res.status(403).end(); 14 | } else { 15 | res.writeHead(200, { 16 | 'Content-Type': 'text/event-stream', 17 | 'Cache-Control': 'no-cache', 18 | 'Connection': 'keep-alive', 19 | 'X-Accel-Buffering': 'no' 20 | }); 21 | subscribers.push(res); 22 | 23 | req.on("close", () => { 24 | subscribers = subscribers.filter(item => item !== res); 25 | }); 26 | } 27 | }) 28 | } 29 | 30 | const sendMessage = (data) => { 31 | const json = JSON.stringify(data); 32 | for(var i = 0; i < subscribers.length; i++) { 33 | try{ 34 | subscribers[i].write(`data: ${json}\n\n`); 35 | } catch(e){ 36 | } 37 | } 38 | } 39 | 40 | module.exports = { 41 | subscribe, 42 | sendMessage, 43 | THEME_INSTALLED, 44 | ORDER_RECEIVED, 45 | ORDER_CHANGED 46 | } 47 | -------------------------------------------------------------------------------- /src/api/server/lib/mongo.js: -------------------------------------------------------------------------------- 1 | const settings = require('./settings'); 2 | const winston = require('winston'); 3 | const mongo = require('mongodb').MongoClient; 4 | const mongodbConnection = settings.mongodbServerUrl; 5 | 6 | const CONNECT_OPTIONS = { 7 | reconnectTries: 3600, 8 | reconnectInterval: 1000 9 | } 10 | 11 | // Initialize connection once 12 | mongo.connect(mongodbConnection, CONNECT_OPTIONS, (err, database) => { 13 | if(err){ 14 | winston.error('Failed connecting to MongoDB', err.message); 15 | } else { 16 | module.exports.db = database; 17 | winston.info('Successfully connected to MongoDB') 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /src/api/server/lib/settings.js: -------------------------------------------------------------------------------- 1 | const settings = require('../../../../config/server'); 2 | module.exports = settings; 3 | -------------------------------------------------------------------------------- /src/api/server/lib/utils.js: -------------------------------------------------------------------------------- 1 | var SitemapService = require('../services/sitemap'); 2 | 3 | var slug = require('slug'); 4 | var slugConfig = { 5 | symbols: false, // replace unicode symbols or not 6 | remove: null, // (optional) regex to remove characters 7 | lower: true // result in lower case 8 | }; 9 | 10 | const cleanSlug = (text) => { 11 | return slug(text || '', slugConfig); 12 | } 13 | 14 | const getAvailableSlug = (path, resource, enableCleanPath = true) => { 15 | return SitemapService.getPaths() 16 | .then(paths => { 17 | if(enableCleanPath){ 18 | path = cleanSlug(path); 19 | } 20 | 21 | let pathExists = paths.find(e => e.path === '/' + path && e.resource != resource); 22 | while(pathExists) { 23 | path += '-2'; 24 | pathExists = paths.find(e => e.path === '/' + path && e.resource != resource); 25 | } 26 | return path; 27 | }) 28 | } 29 | 30 | const getCorrectFileName = (filename) => { 31 | if(filename){ 32 | // replace unsafe characters 33 | return filename.replace(/[\s*/:;&?@$()<>#%\{\}|\\\^\~\[\]]/g, '-'); 34 | } else { 35 | return filename; 36 | } 37 | } 38 | 39 | module.exports = { 40 | cleanSlug: cleanSlug, 41 | getAvailableSlug: getAvailableSlug, 42 | getCorrectFileName: getCorrectFileName 43 | } 44 | -------------------------------------------------------------------------------- /src/api/server/routes/apps.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | const AppSettingsService = require('../services/apps/settings'); 5 | 6 | class AppsRoute { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/apps/:key/settings', security.checkUserScope.bind(this, security.scope.READ_SETTINGS), this.getSettings.bind(this)); 14 | this.router.put('/v1/apps/:key/settings', security.checkUserScope.bind(this, security.scope.WRITE_SETTINGS), this.updateSettings.bind(this)); 15 | } 16 | 17 | getSettings(req, res, next) { 18 | AppSettingsService.getSettings(req.params.key).then(data => { 19 | res.send(data) 20 | }).catch(next); 21 | } 22 | 23 | updateSettings(req, res, next) { 24 | AppSettingsService.updateSettings(req.params.key, req.body).then(data => { 25 | if (data) { 26 | res.send(data) 27 | } else { 28 | res.status(404).end() 29 | } 30 | }).catch(next); 31 | } 32 | } 33 | 34 | module.exports = AppsRoute; 35 | -------------------------------------------------------------------------------- /src/api/server/routes/files.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | const FilesService = require('../services/files'); 5 | 6 | class FilesRoute { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/files', security.checkUserScope.bind(this, security.scope.READ_FILES), this.getFiles.bind(this)); 14 | this.router.post('/v1/files', security.checkUserScope.bind(this, security.scope.WRITE_FILES), this.uploadFile.bind(this)); 15 | this.router.delete('/v1/files/:file', security.checkUserScope.bind(this, security.scope.WRITE_FILES), this.deleteFile.bind(this)); 16 | } 17 | 18 | getFiles(req, res, next) { 19 | FilesService.getFiles() 20 | .then((data) => { 21 | res.send(data) 22 | }) 23 | .catch(next); 24 | } 25 | 26 | uploadFile(req, res, next) { 27 | FilesService.uploadFile(req, res, next); 28 | } 29 | 30 | deleteFile(req, res, next) { 31 | FilesService.deleteFile(req.params.file).then(() => { 32 | res.end() 33 | }).catch(next) 34 | } 35 | } 36 | 37 | module.exports = FilesRoute; 38 | -------------------------------------------------------------------------------- /src/api/server/routes/notifications.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const PaymentGateways = require('../paymentGateways'); 4 | 5 | class NotificationsRoute { 6 | constructor(router) { 7 | this.router = router; 8 | this.registerRoutes(); 9 | } 10 | 11 | registerRoutes() { 12 | this.router.post('/v1/notifications/:gateway', this.paymentNotification.bind(this)); 13 | } 14 | 15 | paymentNotification(req, res, next) { 16 | PaymentGateways.paymentNotification(req, res, req.params.gateway); 17 | } 18 | } 19 | 20 | module.exports = NotificationsRoute; 21 | -------------------------------------------------------------------------------- /src/api/server/routes/paymentGateways.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | var PaymentGatewaysService = require('../services/settings/paymentGateways'); 5 | 6 | class PaymentGatewaysRoute { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/payment_gateways/:name', security.checkUserScope.bind(this, security.scope.READ_PAYMENT_METHODS), this.getGateway.bind(this)); 14 | this.router.put('/v1/payment_gateways/:name', security.checkUserScope.bind(this, security.scope.WRITE_PAYMENT_METHODS), this.updateGateway.bind(this)); 15 | } 16 | 17 | getGateway(req, res, next) { 18 | PaymentGatewaysService.getGateway(req.params.name).then(data => { 19 | res.send(data) 20 | }).catch(next); 21 | } 22 | 23 | updateGateway(req, res, next) { 24 | PaymentGatewaysService.updateGateway(req.params.name, req.body).then(data => { 25 | res.send(data); 26 | }).catch(next); 27 | } 28 | } 29 | 30 | module.exports = PaymentGatewaysRoute; 31 | -------------------------------------------------------------------------------- /src/api/server/routes/sitemap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const security = require('../lib/security'); 4 | var SitemapService = require('../services/sitemap'); 5 | 6 | class SitemapRoute { 7 | constructor(router) { 8 | this.router = router; 9 | this.registerRoutes(); 10 | } 11 | 12 | registerRoutes() { 13 | this.router.get('/v1/sitemap', security.checkUserScope.bind(this, security.scope.READ_SITEMAP), this.getPaths.bind(this)); 14 | } 15 | 16 | getPaths(req, res, next) { 17 | if (req.query.path) { 18 | SitemapService.getSinglePath(req.query.path, req.query.enabled).then((data) => { 19 | if (data) { 20 | res.send(data) 21 | } else { 22 | res.status(404).end() 23 | } 24 | }).catch(next); 25 | } else { 26 | SitemapService.getPaths(req.query.enabled).then((data) => { 27 | res.send(data) 28 | }).catch(next); 29 | } 30 | } 31 | } 32 | 33 | module.exports = SitemapRoute; 34 | -------------------------------------------------------------------------------- /src/api/server/services/apps/settings.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mongo = require('../../lib/mongo'); 4 | var parse = require('../../lib/parse'); 5 | 6 | class AppSettingsService { 7 | constructor() {} 8 | 9 | getSettings(appKey) { 10 | return mongo.db.collection('appSettings').findOne({key: appKey}, { _id: 0, key: 0 }); 11 | } 12 | 13 | updateSettings(appKey, data) { 14 | if (Object.keys(data).length === 0) { 15 | return new Error('Required fields are missing'); 16 | } 17 | 18 | delete data.key; 19 | 20 | return mongo.db.collection('appSettings').updateOne({key: appKey}, { 21 | $set: data 22 | }, {upsert: true}).then(res => this.getSettings(appKey)); 23 | } 24 | } 25 | 26 | module.exports = new AppSettingsService(); 27 | -------------------------------------------------------------------------------- /src/api/server/services/data.js: -------------------------------------------------------------------------------- 1 | // 'use strict'; 2 | // 3 | // const fs = require('fs') 4 | // const path = require('path') 5 | // const countriesArray = require('../../../../data/countries.json'); 6 | // const currenciesArray = require('../../../../data/currencies.json'); 7 | // 8 | // class DataService { 9 | // getCountries() { 10 | // return countriesArray; 11 | // } 12 | // 13 | // getCurrencies() { 14 | // return currenciesArray; 15 | // } 16 | // } 17 | // 18 | // module.exports = new DataService(); 19 | -------------------------------------------------------------------------------- /src/api/server/services/orders/paymentMethodsLight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mongo = require('../../lib/mongo'); 4 | 5 | class PaymentMethodsLightService { 6 | constructor() {} 7 | 8 | getMethods(filter = {}) { 9 | return mongo.db.collection('paymentMethods').find(filter).toArray().then(items => items.map(item => this.changeProperties(item))) 10 | } 11 | 12 | changeProperties(item) { 13 | if (item) { 14 | item.id = item._id.toString(); 15 | delete item._id; 16 | } 17 | return item; 18 | } 19 | } 20 | 21 | module.exports = new PaymentMethodsLightService(); 22 | -------------------------------------------------------------------------------- /src/api/server/services/orders/shippingMethodsLight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mongo = require('../../lib/mongo'); 4 | var ObjectID = require('mongodb').ObjectID; 5 | 6 | class ShippingMethodsLightService { 7 | constructor() {} 8 | 9 | getMethods(filter = {}) { 10 | return mongo.db.collection('shippingMethods').find(filter).toArray().then(items => items.map(item => this.changeProperties(item))); 11 | } 12 | 13 | getMethodPrice(id) { 14 | let filter = {}; 15 | if (id) { 16 | filter._id = new ObjectID(id); 17 | } 18 | 19 | return this.getMethods(filter).then(methods => { 20 | return methods.length > 0 21 | ? methods[0].price || 0 22 | : 0 23 | }) 24 | } 25 | 26 | changeProperties(item) { 27 | if (item) { 28 | item.id = item._id.toString(); 29 | delete item._id; 30 | } 31 | return item; 32 | } 33 | } 34 | 35 | module.exports = new ShippingMethodsLightService(); 36 | -------------------------------------------------------------------------------- /src/api/server/services/settings/paymentGateways.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var mongo = require('../../lib/mongo'); 4 | 5 | class PaymentGatewaysService { 6 | constructor() {} 7 | 8 | getGateway(gatewayName) { 9 | return mongo.db.collection('paymentGateways').findOne({name: gatewayName}).then(data => { 10 | return this.changeProperties(data); 11 | }); 12 | } 13 | 14 | updateGateway(gatewayName, data) { 15 | if (Object.keys(data).length === 0) { 16 | return this.getGateway(gatewayName); 17 | } else { 18 | return mongo.db.collection('paymentGateways') 19 | .updateOne( 20 | { name: gatewayName }, 21 | { $set: data }, 22 | { upsert: true }) 23 | .then(res => this.getGateway(gatewayName)); 24 | } 25 | } 26 | 27 | changeProperties(data) { 28 | if (data) { 29 | delete data._id; 30 | delete data.name; 31 | } 32 | return data; 33 | } 34 | } 35 | 36 | module.exports = new PaymentGatewaysService(); 37 | -------------------------------------------------------------------------------- /src/store/client/api.js: -------------------------------------------------------------------------------- 1 | import CezerinClient from 'cezerin-client' 2 | import clientSettings from './settings' 3 | 4 | const api = new CezerinClient({ 5 | ajaxBaseUrl: clientSettings.ajaxBaseUrl || '/ajax' 6 | }); 7 | 8 | export default api; 9 | -------------------------------------------------------------------------------- /src/store/client/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import {createStore, applyMiddleware} from 'redux' 4 | import {Provider} from 'react-redux' 5 | import thunkMiddleware from 'redux-thunk' 6 | import { BrowserRouter } from 'react-router-dom' 7 | import reducers from '../shared/reducers' 8 | import * as analytics from '../shared/analytics' 9 | import App from '../shared/app' 10 | 11 | const initialState = window.__APP_STATE__; 12 | const store = createStore(reducers, initialState, applyMiddleware(thunkMiddleware)); 13 | 14 | ReactDOM.hydrate( 15 | 16 | 17 | 18 | 19 | , 20 | document.getElementById('app')) 21 | 22 | analytics.onPageLoad({ state: initialState }); 23 | -------------------------------------------------------------------------------- /src/store/client/settings.js: -------------------------------------------------------------------------------- 1 | import settings from '../../../config/store' 2 | export default settings 3 | -------------------------------------------------------------------------------- /src/store/server/api.js: -------------------------------------------------------------------------------- 1 | import jwt from 'jsonwebtoken' 2 | import CezerinClient from 'cezerin-client' 3 | import serverSettings from './settings' 4 | 5 | const TOKEN_PAYLOAD = {email: 'store', scopes: ['admin']}; 6 | const STORE_ACCESS_TOKEN = jwt.sign(TOKEN_PAYLOAD, serverSettings.jwtSecretKey); 7 | 8 | const api = new CezerinClient({ 9 | apiBaseUrl: serverSettings.apiBaseUrl, 10 | ajaxBaseUrl: serverSettings.ajaxBaseUrl, 11 | apiToken: STORE_ACCESS_TOKEN 12 | }); 13 | 14 | export default api; 15 | -------------------------------------------------------------------------------- /src/store/server/readIndexHtml.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | const FILE_PATH = path.resolve('theme/assets/index.html'); 5 | export let indexHtml = null; 6 | 7 | fs.readFile(FILE_PATH, 'utf8', (err, data) => { 8 | indexHtml = err ? err : data; 9 | }); 10 | -------------------------------------------------------------------------------- /src/store/server/robotsRendering.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import api from './api' 4 | 5 | const ROBOTS_TEMPLATE_PATH = 'public/robots.template'; 6 | 7 | const robotsRendering = (req, res) => { 8 | api.settings.retrieve().then(settingsResponse => { 9 | fs.readFile(path.resolve(ROBOTS_TEMPLATE_PATH), 'utf8', (err, data) => { 10 | if(err) { 11 | res.status(500).end(); 12 | } else { 13 | const robots = data.replace(/{domain}/g, settingsResponse.json.domain) 14 | res.header('Content-Type', 'text/plain'); 15 | res.send(robots); 16 | } 17 | }); 18 | }) 19 | } 20 | 21 | export default robotsRendering; 22 | -------------------------------------------------------------------------------- /src/store/server/settings.js: -------------------------------------------------------------------------------- 1 | import settings from '../../../config/server' 2 | export default settings 3 | -------------------------------------------------------------------------------- /src/store/server/sitemapRendering.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import sm from 'sitemap' 3 | import api from './api' 4 | 5 | const SITEMAP_EXCLUDE_PATH = ['/', '/checkout', '/checkout-success', '/account', '/cart', '/login', '/logout', '/register']; 6 | 7 | const sitemapRendering = (req, res) => { 8 | Promise.all([ 9 | api.sitemap.list({ enabled: true }), 10 | api.settings.retrieve() 11 | ]).then(([sitemapResponse, settingsResponse]) => { 12 | const urls = sitemapResponse.json.filter(item => item.type !== 'reserved' && item.type !== 'search' && !SITEMAP_EXCLUDE_PATH.includes(item.path)).map(item => item.path) 13 | const sitemap = sm.createSitemap ({ 14 | hostname: settingsResponse.json.domain, 15 | urls: urls 16 | }); 17 | sitemap.toXML((err, xml) => { 18 | if (err) { 19 | res.status(500).end(); 20 | } 21 | res.header('Content-Type', 'application/xml'); 22 | res.send(xml); 23 | }); 24 | }) 25 | } 26 | 27 | export default sitemapRendering; 28 | -------------------------------------------------------------------------------- /src/store/server/themeLocales.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | const THEME_LOCALES_PATH = 'theme/locales/'; 5 | let text = null; 6 | 7 | export const getText = (locale) => { 8 | if(text) { 9 | return Promise.resolve(text); 10 | } else { 11 | const filePath = path.resolve(THEME_LOCALES_PATH + locale + '.json'); 12 | return new Promise((resolve, reject) => { 13 | fs.readFile(filePath, 'utf8', (err, data) => { 14 | if(err){ 15 | reject(err) 16 | } else { 17 | text = JSON.parse(data); 18 | resolve(text); 19 | } 20 | }); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/store/shared/components/checkoutForm/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import Form from './form' 5 | 6 | const mapStateToProps = (state, ownProps) => { 7 | return { 8 | cart: state.app.cart, 9 | settings: state.app.settings, 10 | themeSettings: state.app.themeSettings 11 | } 12 | } 13 | 14 | const mapDispatchToProps = (dispatch, ownProps) => { 15 | return { 16 | onLoad: () => {} 17 | } 18 | } 19 | 20 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form)); 21 | -------------------------------------------------------------------------------- /src/store/shared/components/stepPayment/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {checkout} from '../../actions' 5 | import Form from './form' 6 | 7 | const mapStateToProps = (state, ownProps) => { 8 | return { 9 | cart: state.app.cart, 10 | settings: state.app.settings, 11 | processingCheckout: state.app.processingCheckout 12 | } 13 | } 14 | 15 | const mapDispatchToProps = (dispatch, ownProps) => { 16 | return { 17 | finishCheckout: () => { 18 | dispatch(checkout(null, ownProps.history)); 19 | } 20 | } 21 | } 22 | 23 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form)); 24 | -------------------------------------------------------------------------------- /src/store/shared/containers/category.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {CategoryContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CategoryContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/containers/checkout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {CheckoutContainer} from 'theme' 6 | import CheckoutForm from '../components/checkoutForm' 7 | 8 | const ConnectedCheckoutContainer = withRouter(connect(mapStateToProps, mapDispatchToProps)(CheckoutContainer)); 9 | 10 | export default() => { 11 | return } /> 12 | } 13 | -------------------------------------------------------------------------------- /src/store/shared/containers/checkoutSuccess.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {CheckoutSuccessContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CheckoutSuccessContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/containers/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {IndexContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IndexContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/containers/notfound.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {NotFoundContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(NotFoundContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/containers/page.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {PageContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PageContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/containers/product.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {ProductContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(ProductContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/containers/search.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {SearchContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(SearchContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/containers/shared.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {connect} from 'react-redux' 3 | import {withRouter} from 'react-router' 4 | import {mapStateToProps, mapDispatchToProps} from '../containerProps' 5 | import {SharedContainer} from 'theme' 6 | 7 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(SharedContainer)); 8 | -------------------------------------------------------------------------------- /src/store/shared/pageTypes.js: -------------------------------------------------------------------------------- 1 | export const PAGE = 'page' 2 | export const PRODUCT_CATEGORY = 'product-category' 3 | export const PRODUCT = 'product' 4 | export const RESERVED = 'reserved' 5 | export const SEARCH = 'search' 6 | -------------------------------------------------------------------------------- /src/store/shared/text.js: -------------------------------------------------------------------------------- 1 | import clientSettings from '../client/settings' 2 | module.exports = require('../../../locales/store/' + clientSettings.language + '.json'); 3 | -------------------------------------------------------------------------------- /theme/assets/css/cart.scss: -------------------------------------------------------------------------------- 1 | .mini-cart { 2 | position: absolute; 3 | width: 460px; 4 | top: calc(100%); 5 | right: calc(-100%); 6 | background: #fff; 7 | z-index: 99; 8 | box-shadow: 2px 2px 1px 0 rgba(0,0,0,0.2); 9 | border: 1px solid #f3f3f3; 10 | border-width: 1px 0 0 1px; 11 | transition: right 200ms ease-in-out; 12 | padding: 20px; 13 | text-align: left; 14 | font-size: 90%; 15 | } 16 | 17 | .mini-cart-open .mini-cart { 18 | right: 0; 19 | } 20 | 21 | .mini-cart-item-price { 22 | padding-bottom: 6px 23 | } 24 | 25 | .cart-option-name { 26 | color: #999; 27 | } 28 | 29 | .cart-quantity { 30 | color: #999; 31 | } 32 | 33 | .mini-cart .product-old-price { 34 | padding-right: 10px; 35 | color: #636363; 36 | } 37 | 38 | .mini-cart .product-new-price { 39 | color: #e72b1e; 40 | } 41 | 42 | .mini-cart .product-option { 43 | margin-bottom: 15px; 44 | } 45 | 46 | .mini-cart .product-option-name { 47 | color: #777; 48 | } 49 | 50 | /* 51 | Mobile 52 | */ 53 | @media screen and (max-width: 768px) { 54 | .mini-cart { 55 | top: 3.25rem; 56 | position: fixed; 57 | width: 90%; 58 | z-index: 1002; 59 | bottom: 0; 60 | overflow-y: scroll; 61 | font-size: 82%; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /theme/assets/css/custom.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/css/custom.scss -------------------------------------------------------------------------------- /theme/assets/css/page.scss: -------------------------------------------------------------------------------- 1 | .page-list { 2 | margin: 40px 0 0 0; 3 | } 4 | .page-item { 5 | margin: 0 0 30px 0; 6 | border-bottom: 1px solid #e5e5e5; 7 | } 8 | .page-item h2 { 9 | font-size: 1.5rem; 10 | margin: 0 0 10px 0; 11 | } 12 | .page-item h2 a:hover { 13 | text-decoration: underline; 14 | } 15 | .page-item .date { 16 | font-size: small; 17 | color: #aaa; 18 | margin: 0 0 10px 0; 19 | } 20 | .page-item .description { 21 | margin: 0 0 10px 0; 22 | } 23 | .page-item div:last-of-type { 24 | margin: 0 0 40px 0; 25 | } 26 | .page-list div:last-of-type { 27 | border-bottom: none; 28 | } 29 | .page-content a { 30 | text-decoration: underline; 31 | } 32 | -------------------------------------------------------------------------------- /theme/assets/images/arrow_back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /theme/assets/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /theme/assets/images/arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /theme/assets/images/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /theme/assets/images/icons/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/icons/icon-128.png -------------------------------------------------------------------------------- /theme/assets/images/icons/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/icons/icon-16.png -------------------------------------------------------------------------------- /theme/assets/images/icons/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/icons/icon-256.png -------------------------------------------------------------------------------- /theme/assets/images/icons/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/icons/icon-32.png -------------------------------------------------------------------------------- /theme/assets/images/icons/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/icons/icon-512.png -------------------------------------------------------------------------------- /theme/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/logo.png -------------------------------------------------------------------------------- /theme/assets/images/payment/diners.svg: -------------------------------------------------------------------------------- 1 | diners -------------------------------------------------------------------------------- /theme/assets/images/payment/visa.svg: -------------------------------------------------------------------------------- 1 | Slice 1 -------------------------------------------------------------------------------- /theme/assets/images/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /theme/assets/images/slide7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/slide7.jpg -------------------------------------------------------------------------------- /theme/assets/images/slide8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/slide8.jpg -------------------------------------------------------------------------------- /theme/assets/images/slide9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/React-Ecommerce/252043b873c935047557afc094a9a198720a066c/theme/assets/images/slide9.jpg -------------------------------------------------------------------------------- /theme/assets/images/success.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /theme/assets/images/thin_arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /theme/assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "The Shop", 3 | "short_name": "The Shop", 4 | "start_url": "/", 5 | "display": "standalone", 6 | "background_color": "#F9F9F9", 7 | "theme_color": "#f5f5f5", 8 | "icons": [{ 9 | "src": "/assets/images/icons/icon-16.png", 10 | "sizes": "16x16", 11 | "type": "image/png" 12 | },{ 13 | "src": "/assets/images/icons/icon-32.png", 14 | "sizes": "32x32", 15 | "type": "image/png" 16 | },{ 17 | "src": "/assets/images/icons/icon-128.png", 18 | "sizes": "128x128", 19 | "type": "image/png" 20 | },{ 21 | "src": "/assets/images/icons/icon-256.png", 22 | "sizes": "256x256", 23 | "type": "image/png" 24 | },{ 25 | "src": "/assets/images/icons/icon-512.png", 26 | "sizes": "512x512", 27 | "type": "image/png" 28 | }] 29 | } 30 | -------------------------------------------------------------------------------- /theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "theme", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "babel src -d dist --quiet" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "babel-cli": "^6.26.0", 13 | "babel-core": "^6.26.0", 14 | "babel-loader": "^7.1.2", 15 | "babel-plugin-transform-class-properties": "^6.24.1", 16 | "babel-preset-latest": "^6.24.1", 17 | "babel-preset-react": "^6.24.1", 18 | "bulma": "^0.6.1", 19 | "rc-slider": "^8.4.1", 20 | "react-image-gallery": "^0.8.6", 21 | "react-image-lightbox": "^4.3.0", 22 | "react-lazyload": "^2.3.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /theme/src/components/cartIndicator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink } from 'react-router-dom' 3 | import { themeSettings, text } from '../lib/settings' 4 | 5 | const CartCount = ({ cart }) => { 6 | if (cart && cart.items && cart.items.length > 0) { 7 | let itemsCount = cart.items.reduce((a, b) => a + b.quantity, 0); 8 | return {itemsCount}; 9 | } else { 10 | return null; 11 | } 12 | } 13 | 14 | const CartIcon = ({ cartIsActive }) => { 15 | if(cartIsActive){ 16 | return {text.close} 17 | } else { 18 | return {text.cart} 19 | } 20 | } 21 | 22 | export default class CartIndicator extends React.PureComponent { 23 | render() { 24 | const { cart, onClick, cartIsActive } = this.props; 25 | return 26 | 27 | 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /theme/src/components/categoryBreadcrumbs.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { NavLink } from 'react-router-dom' 3 | import { themeSettings, text } from '../lib/settings' 4 | import * as helper from '../lib/helper' 5 | 6 | const CategoryBreadcrumbs = ({ currentCategory, categories }) => { 7 | const items = helper.getCategoryBreadcrumbs(currentCategory.id, categories); 8 | return ( 9 | 20 | ) 21 | } 22 | 23 | export default CategoryBreadcrumbs; 24 | -------------------------------------------------------------------------------- /theme/src/components/head/cartIndicator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink } from 'react-router-dom' 3 | import { themeSettings, text } from '../../lib/settings' 4 | 5 | const CartCount = ({ cart }) => { 6 | if (cart && cart.items && cart.items.length > 0) { 7 | let itemsCount = cart.items.reduce((a, b) => a + b.quantity, 0); 8 | return {itemsCount}; 9 | } else { 10 | return null; 11 | } 12 | } 13 | 14 | const CartIcon = ({ cartIsActive }) => { 15 | if(cartIsActive){ 16 | return {text.close} 17 | } else { 18 | return {text.cart} 19 | } 20 | } 21 | 22 | export default class CartIndicator extends React.PureComponent { 23 | render() { 24 | const { cart, onClick, cartIsActive } = this.props; 25 | return 26 | 27 | 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /theme/src/components/header/cartIndicator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink } from 'react-router-dom' 3 | import { themeSettings, text } from '../../lib/settings' 4 | 5 | const CartCount = ({ cart }) => { 6 | if (cart && cart.items && cart.items.length > 0) { 7 | let itemsCount = cart.items.reduce((a, b) => a + b.quantity, 0); 8 | return {itemsCount}; 9 | } else { 10 | return null; 11 | } 12 | } 13 | 14 | const CartIcon = ({ cartIsActive }) => { 15 | if(cartIsActive){ 16 | return {text.close} 17 | } else { 18 | return {text.cart} 19 | } 20 | } 21 | 22 | export default class CartIndicator extends React.PureComponent { 23 | render() { 24 | const { cart, onClick, cartIsActive } = this.props; 25 | return 26 | 27 | 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /theme/src/components/pageList/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import api from '../../lib/api' 3 | import PageList from './list' 4 | 5 | export default class CustomPageList extends React.Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | pages: [] 10 | } 11 | } 12 | 13 | componentDidMount() { 14 | this.fetchData(this.props); 15 | } 16 | 17 | componentWillReceiveProps(nextProps) { 18 | this.fetchData(nextProps); 19 | } 20 | 21 | fetchData = ({ tags, sort }) => { 22 | const filter = { 23 | tags: tags, 24 | sort: sort 25 | }; 26 | 27 | api.ajax.pages.list(filter).then(({status, json}) => { 28 | this.setState({ 29 | pages: json 30 | }) 31 | }); 32 | } 33 | 34 | render() { 35 | const { pages } = this.state; 36 | return ( 37 | 38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /theme/src/components/pageList/item.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { NavLink } from 'react-router-dom' 3 | import { themeSettings, text } from '../../lib/settings' 4 | 5 | const pad = number => number < 10 ? ('0' + number) : number; 6 | const formatDate = date => `${pad(date.getDate())}.${pad(date.getMonth() + 1)}.${date.getFullYear()}`; 7 | 8 | const PageListItem = ({page}) => ( 9 |
10 |

{page.meta_title}

11 |
12 | {formatDate(new Date(page.date_created))} 13 |
14 |
15 | {page.meta_description} 16 |
17 |
18 | ) 19 | 20 | export default PageListItem 21 | -------------------------------------------------------------------------------- /theme/src/components/pageList/list.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../../lib/settings' 3 | import PageListItem from './item' 4 | 5 | const PageList = ({pages}) => { 6 | const items = pages ? pages.map((page, index) => ( 7 | 8 | )) : null; 9 | 10 | return ( 11 |
12 | {items} 13 |
14 | ) 15 | } 16 | 17 | export default PageList 18 | -------------------------------------------------------------------------------- /theme/src/components/productDetails/attributes.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../../lib/settings' 3 | 4 | const Attribute = ({ name, value }) => ( 5 |
6 |
7 | {name}: 8 |
9 |
10 | {value} 11 |
12 |
13 | ) 14 | 15 | const Attributes = ({ attributes }) => { 16 | if(attributes && attributes.length > 0) { 17 | const items = attributes.map((attribute, index) => ( 18 | 19 | )) 20 | 21 | return ( 22 |
23 |
{text.attributes}
24 | {items} 25 |
26 | ) 27 | } else { 28 | return null; 29 | } 30 | } 31 | export default Attributes; 32 | -------------------------------------------------------------------------------- /theme/src/components/productDetails/breadcrumbs.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { NavLink } from 'react-router-dom' 3 | import { themeSettings, text } from '../../lib/settings' 4 | import * as helper from '../../lib/helper' 5 | 6 | const ProductBreadcrumbs = ({ product, categories }) => { 7 | const items = helper.getProductBreadcrumbs(product, categories); 8 | return ( 9 | 17 | ) 18 | } 19 | 20 | export default ProductBreadcrumbs; 21 | -------------------------------------------------------------------------------- /theme/src/components/productDetails/relatedProducts.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../../lib/settings' 3 | import CustomProducts from '../products/custom' 4 | const Fragment = React.Fragment; 5 | 6 | export default class RelatedProducts extends React.PureComponent { 7 | constructor(props) { 8 | super(props); 9 | } 10 | 11 | render() { 12 | const { ids, settings, addCartItem, limit } = this.props; 13 | if(ids && ids.length > 0) { 14 | let title = themeSettings.related_products_title && themeSettings.related_products_title.length > 0 15 | ? themeSettings.related_products_title 16 | : text.relatedProducts; 17 | 18 | return ( 19 |
20 |
21 |
{title}
22 | 30 |
31 |
32 | ) 33 | } else { 34 | return null; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /theme/src/components/productDetails/tags.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import * as helper from '../../lib/helper' 3 | import { themeSettings, text } from '../../lib/settings' 4 | 5 | const Tags = ({ tags }) => { 6 | if(tags && tags.length > 0){ 7 | return ( 8 |
9 | {tags.map((tag, index) => ( 10 | {tag} 11 | ))} 12 |
13 | ) 14 | } else { 15 | return null; 16 | } 17 | } 18 | 19 | export default Tags; 20 | -------------------------------------------------------------------------------- /theme/src/components/productList/itemImage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../../lib/settings' 3 | import * as helper from '../../lib/helper' 4 | import LazyLoad from 'react-lazyload' 5 | 6 | const ItemImage = ({ images, alt, title, height }) => { 7 | if(images && images.length > 0) { 8 | const imageUrl = helper.getThumbnailUrl(images[0].url, themeSettings.listThumbnailWidth); 9 | 10 | return ( 11 | 12 | {alt} 13 | 14 | ) 15 | } else { 16 | return ( 17 |
18 | ) 19 | } 20 | } 21 | 22 | export default ItemImage 23 | -------------------------------------------------------------------------------- /theme/src/components/productList/itemTags.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../../lib/settings' 3 | import * as helper from '../../lib/helper' 4 | 5 | const ItemTags = ({ tags }) => { 6 | if(tags && tags.length > 0){ 7 | return
8 | {tags.map((tag, index) => ( 9 | {tag} 10 | ))} 11 |
12 | } else { 13 | return null; 14 | } 15 | } 16 | 17 | export default ItemTags 18 | -------------------------------------------------------------------------------- /theme/src/components/productList/loadMore.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../../lib/settings' 3 | 4 | const LoadMore = ({ loadMoreProducts, hasMore, loading, className }) => { 5 | if(hasMore){ 6 | className = className || 'button is-fullwidth is-dark'; 7 | 8 | let buttonStyle = {}; 9 | if(themeSettings.button_loadmore_bg && themeSettings.button_loadmore_bg.length > 0){ 10 | buttonStyle.backgroundColor = themeSettings.button_loadmore_bg; 11 | } 12 | if(themeSettings.button_loadmore_color && themeSettings.button_loadmore_color.length > 0){ 13 | buttonStyle.color = themeSettings.button_loadmore_color; 14 | } 15 | 16 | const loadMoreText = themeSettings.button_loadmore_text && themeSettings.button_loadmore_text.length > 0 ? themeSettings.button_loadmore_text : text.loadMore; 17 | 18 | return ( 19 | 20 | ) 21 | } else { 22 | return null; 23 | } 24 | } 25 | 26 | export default LoadMore 27 | -------------------------------------------------------------------------------- /theme/src/components/sort.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../lib/settings' 3 | 4 | const Sort = ({ defaultSort, currentSort, setSort }) => { 5 | return ( 6 |
7 |
{text.sort}:
8 |
9 | 10 | 16 | 17 |
18 |
19 | ) 20 | } 21 | 22 | export default Sort 23 | -------------------------------------------------------------------------------- /theme/src/containers/checkout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../lib/settings' 3 | import MetaTags from '../components/metaTags' 4 | import OrderSummary from '../components/orderSummary' 5 | const Fragment = React.Fragment; 6 | 7 | const CheckoutContainer = (props) => { 8 | const {pageDetails} = props.state; 9 | const {checkoutForm} = props; 10 | 11 | return ( 12 | 13 | 20 | 21 |
22 |
23 |
24 |
25 | 26 |
27 |
28 | {checkoutForm} 29 |
30 |
31 |
32 |
33 |
34 | ) 35 | } 36 | 37 | export default CheckoutContainer 38 | -------------------------------------------------------------------------------- /theme/src/containers/notfound.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../lib/settings' 3 | import MetaTags from '../components/metaTags' 4 | const Fragment = React.Fragment; 5 | 6 | const NotFoundContainer = (props) => ( 7 | 8 | 11 |
12 |
13 |
14 |

{text.title404}

15 | {text.text404} 16 |
17 |
18 |
19 |
20 | ) 21 | 22 | export default NotFoundContainer 23 | -------------------------------------------------------------------------------- /theme/src/containers/shared.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { themeSettings, text } from '../lib/settings' 3 | import Header from '../components/header' 4 | import Footer from '../components/footer' 5 | const Fragment = React.Fragment; 6 | 7 | const SharedContainer = (props) => { 8 | const {currentPage, settings} = props.state; 9 | let hideFooter = (currentPage.path === '/checkout-success' || currentPage.path === '/checkout') && themeSettings.hide_footer_on_checkout === true; 10 | 11 | return ( 12 | 13 |
14 | {props.children} 15 | {!hideFooter && 16 |