disco_app 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +37 -0
  3. data/app/assets/images/disco_app/icon.svg +1 -0
  4. data/app/assets/images/disco_app/icons.svg +0 -0
  5. data/app/assets/javascripts/disco_app/components/custom/filterable_shop_list.js.jsx +61 -0
  6. data/app/assets/javascripts/disco_app/components/custom/inline-radio-options.es6.jsx +59 -0
  7. data/app/assets/javascripts/disco_app/components/custom/rules-editor.es6.jsx +417 -0
  8. data/app/assets/javascripts/disco_app/components/custom/shop_filter_query.js.jsx +13 -0
  9. data/app/assets/javascripts/disco_app/components/custom/shop_filter_tab.js.jsx +34 -0
  10. data/app/assets/javascripts/disco_app/components/custom/shop_filter_tabs.js.jsx +21 -0
  11. data/app/assets/javascripts/disco_app/components/custom/shop_list.js.jsx +142 -0
  12. data/app/assets/javascripts/disco_app/components/custom/shop_row.js.jsx +43 -0
  13. data/app/assets/javascripts/disco_app/components/custom/shopify_admin_link.js.jsx +29 -0
  14. data/app/assets/javascripts/disco_app/components/ui-kit/cards/card-section.es6.jsx +30 -0
  15. data/app/assets/javascripts/disco_app/components/ui-kit/cards/card.es6.jsx +9 -0
  16. data/app/assets/javascripts/disco_app/components/ui-kit/cards/cart-section-title.es6.jsx +7 -0
  17. data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_form.es6.jsx +72 -0
  18. data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_input.es6.jsx +20 -0
  19. data/app/assets/javascripts/disco_app/components/ui-kit/forms/button.es6.jsx +13 -0
  20. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-radio.es6.jsx +30 -0
  21. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-select.es6.jsx +39 -0
  22. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-text.es6.jsx +59 -0
  23. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-textarea.es6.jsx +48 -0
  24. data/app/assets/javascripts/disco_app/components/ui-kit/icons/icon-chevron.es6.jsx +33 -0
  25. data/app/assets/javascripts/disco_app/components/ui-kit/icons/next-icon.es6.jsx +18 -0
  26. data/app/assets/javascripts/disco_app/components/ui-kit/input_select.es6.jsx +21 -0
  27. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-annotated-section.es6.jsx +29 -0
  28. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-empty-state.es6.jsx +35 -0
  29. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-footer-help.es6.jsx +13 -0
  30. data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-page-actions.es6.jsx +39 -0
  31. data/app/assets/javascripts/disco_app/components.js +2 -0
  32. data/app/assets/javascripts/disco_app/disco_app.js +9 -0
  33. data/app/assets/javascripts/disco_app/frame.js +152 -0
  34. data/app/assets/javascripts/disco_app/shopify-turbolinks.js +7 -0
  35. data/app/assets/javascripts/disco_app/ui-kit.js +1 -0
  36. data/app/assets/stylesheets/disco_app/admin/_header.scss +75 -0
  37. data/app/assets/stylesheets/disco_app/admin/_layout.scss +32 -0
  38. data/app/assets/stylesheets/disco_app/admin/_nav.scss +184 -0
  39. data/app/assets/stylesheets/disco_app/admin.scss +11 -0
  40. data/app/assets/stylesheets/disco_app/disco_app.scss +19 -0
  41. data/app/assets/stylesheets/disco_app/frame/_buttons.scss +54 -0
  42. data/app/assets/stylesheets/disco_app/frame/_forms.scss +26 -0
  43. data/app/assets/stylesheets/disco_app/frame/_layout.scss +77 -0
  44. data/app/assets/stylesheets/disco_app/frame/_type.scss +25 -0
  45. data/app/assets/stylesheets/disco_app/frame.scss +10 -0
  46. data/app/assets/stylesheets/disco_app/mixins/_flexbox.scss +400 -0
  47. data/app/assets/stylesheets/disco_app/ui-kit/_ui-empty-state.scss +121 -0
  48. data/app/assets/stylesheets/disco_app/ui-kit/_ui-footer-help.scss +28 -0
  49. data/app/assets/stylesheets/disco_app/ui-kit/_ui-icons.scss +28 -0
  50. data/app/assets/stylesheets/disco_app/ui-kit/_ui-kit.scss +5113 -0
  51. data/app/assets/stylesheets/disco_app/ui-kit/_ui-layout.scss +10 -0
  52. data/app/assets/stylesheets/disco_app/ui-kit/_ui-page-actions.scss +21 -0
  53. data/app/assets/stylesheets/disco_app/ui-kit/_ui-tabs.scss +75 -0
  54. data/app/assets/stylesheets/disco_app/ui-kit/_ui-type.scss +13 -0
  55. data/app/controllers/disco_app/admin/app_settings_controller.rb +3 -0
  56. data/app/controllers/disco_app/admin/application_controller.rb +3 -0
  57. data/app/controllers/disco_app/admin/concerns/app_settings_controller.rb +24 -0
  58. data/app/controllers/disco_app/admin/concerns/authenticated_controller.rb +20 -0
  59. data/app/controllers/disco_app/admin/concerns/plans_controller.rb +54 -0
  60. data/app/controllers/disco_app/admin/concerns/shops_controller.rb +7 -0
  61. data/app/controllers/disco_app/admin/concerns/subscriptions_controller.rb +29 -0
  62. data/app/controllers/disco_app/admin/plans_controller.rb +3 -0
  63. data/app/controllers/disco_app/admin/resources/shops_controller.rb +3 -0
  64. data/app/controllers/disco_app/admin/shops_controller.rb +3 -0
  65. data/app/controllers/disco_app/admin/subscriptions_controller.rb +3 -0
  66. data/app/controllers/disco_app/charges_controller.rb +47 -0
  67. data/app/controllers/disco_app/concerns/app_proxy_controller.rb +40 -0
  68. data/app/controllers/disco_app/concerns/authenticated_controller.rb +56 -0
  69. data/app/controllers/disco_app/concerns/carrier_request_controller.rb +21 -0
  70. data/app/controllers/disco_app/frame_controller.rb +9 -0
  71. data/app/controllers/disco_app/install_controller.rb +27 -0
  72. data/app/controllers/disco_app/subscriptions_controller.rb +32 -0
  73. data/app/controllers/disco_app/webhooks_controller.rb +46 -0
  74. data/app/controllers/sessions_controller.rb +28 -0
  75. data/app/helpers/disco_app/application_helper.rb +50 -0
  76. data/app/jobs/disco_app/app_installed_job.rb +3 -0
  77. data/app/jobs/disco_app/app_uninstalled_job.rb +3 -0
  78. data/app/jobs/disco_app/concerns/app_installed_job.rb +39 -0
  79. data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +20 -0
  80. data/app/jobs/disco_app/concerns/render_asset_group_job.rb +8 -0
  81. data/app/jobs/disco_app/concerns/shop_update_job.rb +13 -0
  82. data/app/jobs/disco_app/concerns/subscription_changed_job.rb +7 -0
  83. data/app/jobs/disco_app/concerns/synchronise_carrier_service_job.rb +52 -0
  84. data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +61 -0
  85. data/app/jobs/disco_app/render_asset_group_job.rb +3 -0
  86. data/app/jobs/disco_app/shop_job.rb +27 -0
  87. data/app/jobs/disco_app/shop_update_job.rb +3 -0
  88. data/app/jobs/disco_app/subscription_changed_job.rb +3 -0
  89. data/app/jobs/disco_app/synchronise_carrier_service_job.rb +3 -0
  90. data/app/jobs/disco_app/synchronise_webhooks_job.rb +3 -0
  91. data/app/models/disco_app/app_settings.rb +3 -0
  92. data/app/models/disco_app/application_charge.rb +18 -0
  93. data/app/models/disco_app/concerns/app_settings.rb +7 -0
  94. data/app/models/disco_app/concerns/plan.rb +26 -0
  95. data/app/models/disco_app/concerns/plan_code.rb +15 -0
  96. data/app/models/disco_app/concerns/renders_assets.rb +148 -0
  97. data/app/models/disco_app/concerns/shop.rb +63 -0
  98. data/app/models/disco_app/concerns/subscription.rb +60 -0
  99. data/app/models/disco_app/concerns/synchronises.rb +39 -0
  100. data/app/models/disco_app/plan.rb +3 -0
  101. data/app/models/disco_app/plan_code.rb +3 -0
  102. data/app/models/disco_app/recurring_application_charge.rb +18 -0
  103. data/app/models/disco_app/session_storage.rb +18 -0
  104. data/app/models/disco_app/shop.rb +3 -0
  105. data/app/models/disco_app/subscription.rb +3 -0
  106. data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +100 -0
  107. data/app/resources/disco_app/admin/resources/shop_resource.rb +4 -0
  108. data/app/services/disco_app/carrier_request_service.rb +15 -0
  109. data/app/services/disco_app/charges_service.rb +81 -0
  110. data/app/services/disco_app/proxy_service.rb +17 -0
  111. data/app/services/disco_app/subscription_service.rb +46 -0
  112. data/app/services/disco_app/webhook_service.rb +30 -0
  113. data/app/views/disco_app/admin/app_settings/edit.html.erb +5 -0
  114. data/app/views/disco_app/admin/plans/_form.html.erb +72 -0
  115. data/app/views/disco_app/admin/plans/_plan_code_fields.html.erb +15 -0
  116. data/app/views/disco_app/admin/plans/edit.html.erb +7 -0
  117. data/app/views/disco_app/admin/plans/index.html.erb +43 -0
  118. data/app/views/disco_app/admin/plans/new.html.erb +7 -0
  119. data/app/views/disco_app/admin/shops/index.html.erb +13 -0
  120. data/app/views/disco_app/admin/subscriptions/edit.html.erb +33 -0
  121. data/app/views/disco_app/charges/activate.html.erb +1 -0
  122. data/app/views/disco_app/charges/create.html.erb +1 -0
  123. data/app/views/disco_app/charges/new.html.erb +12 -0
  124. data/app/views/disco_app/frame/frame.html.erb +36 -0
  125. data/app/views/disco_app/install/installing.html.erb +7 -0
  126. data/app/views/disco_app/install/uninstalling.html.erb +1 -0
  127. data/app/views/disco_app/proxy_errors/404.html.erb +1 -0
  128. data/app/views/disco_app/shared/_card.html.erb +14 -0
  129. data/app/views/disco_app/shared/_icons.html.erb +3 -0
  130. data/app/views/disco_app/shared/_section.html.erb +17 -0
  131. data/app/views/disco_app/subscriptions/new.html.erb +25 -0
  132. data/app/views/layouts/admin/_nav_items.erb +20 -0
  133. data/app/views/layouts/admin.html.erb +67 -0
  134. data/app/views/layouts/application.html.erb +18 -0
  135. data/app/views/layouts/embedded_app.html.erb +43 -0
  136. data/app/views/layouts/embedded_app_modal.html.erb +28 -0
  137. data/app/views/sessions/new.html.erb +26 -0
  138. data/config/routes.rb +48 -0
  139. data/db/migrate/20150525000000_create_shops_if_not_existent.rb +15 -0
  140. data/db/migrate/20150525162112_add_status_to_shops.rb +5 -0
  141. data/db/migrate/20150525171422_add_meta_to_shops.rb +11 -0
  142. data/db/migrate/20150629210346_add_charge_status_to_shop.rb +5 -0
  143. data/db/migrate/20150814214025_add_more_meta_to_shops.rb +15 -0
  144. data/db/migrate/20151017231302_create_disco_app_plans.rb +13 -0
  145. data/db/migrate/20151017232027_create_disco_app_subscriptions.rb +15 -0
  146. data/db/migrate/20151017234409_move_shop_to_disco_app_engine.rb +5 -0
  147. data/db/migrate/20160112233706_create_disco_app_sessions.rb +12 -0
  148. data/db/migrate/20160113194418_add_shop_id_to_disco_app_sessions.rb +6 -0
  149. data/db/migrate/20160223111044_create_disco_app_settings.rb +8 -0
  150. data/db/migrate/20160301223215_update_plans.rb +22 -0
  151. data/db/migrate/20160301224558_update_subscriptions.rb +13 -0
  152. data/db/migrate/20160302104816_create_disco_app_recurring_application_charges.rb +14 -0
  153. data/db/migrate/20160302105259_create_disco_app_application_charges.rb +14 -0
  154. data/db/migrate/20160302134728_drop_charge_status_from_shops.rb +5 -0
  155. data/db/migrate/20160302142941_add_shopify_attributes_to_charges.rb +8 -0
  156. data/db/migrate/20160331093148_create_disco_app_plan_codes.rb +14 -0
  157. data/db/migrate/20160401044420_add_status_to_plan_codes.rb +5 -0
  158. data/db/migrate/20160401045551_add_amount_and_plan_code_to_disco_app_subscriptions.rb +7 -0
  159. data/db/migrate/20160425205211_add_source_to_disco_app_subscriptions.rb +5 -0
  160. data/db/migrate/20160426033520_add_trial_period_days_to_disco_app_subscriptions.rb +5 -0
  161. data/db/migrate/20160513140727_add_name_to_disco_app_shops.rb +5 -0
  162. data/db/migrate/20160521135510_move_shop_to_synchronises.rb +61 -0
  163. data/lib/disco_app/configuration.rb +39 -0
  164. data/lib/disco_app/constants.rb +4 -0
  165. data/lib/disco_app/engine.rb +26 -0
  166. data/lib/disco_app/session.rb +14 -0
  167. data/lib/disco_app/support/file_fixtures.rb +23 -0
  168. data/lib/disco_app/test_help.rb +11 -0
  169. data/lib/disco_app/version.rb +3 -0
  170. data/lib/disco_app.rb +7 -0
  171. data/lib/generators/disco_app/USAGE +5 -0
  172. data/lib/generators/disco_app/disco_app_generator.rb +235 -0
  173. data/lib/generators/disco_app/templates/assets/javascripts/application.js +17 -0
  174. data/lib/generators/disco_app/templates/assets/javascripts/components.js +3 -0
  175. data/lib/generators/disco_app/templates/assets/stylesheets/application.scss +5 -0
  176. data/lib/generators/disco_app/templates/config/database.yml.tt +20 -0
  177. data/lib/generators/disco_app/templates/config/newrelic.yml +26 -0
  178. data/lib/generators/disco_app/templates/config/puma.rb +15 -0
  179. data/lib/generators/disco_app/templates/controllers/home_controller.rb +7 -0
  180. data/lib/generators/disco_app/templates/initializers/disco_app.rb +19 -0
  181. data/lib/generators/disco_app/templates/initializers/rollbar.rb +12 -0
  182. data/lib/generators/disco_app/templates/initializers/session_store.rb +2 -0
  183. data/lib/generators/disco_app/templates/initializers/shopify_app.rb +7 -0
  184. data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +7 -0
  185. data/lib/generators/disco_app/templates/root/CHECKS +4 -0
  186. data/lib/generators/disco_app/templates/root/Procfile +2 -0
  187. data/lib/generators/disco_app/templates/views/home/index.html.erb +2 -0
  188. data/lib/tasks/carrier_service.rake +10 -0
  189. data/lib/tasks/database.rake +8 -0
  190. data/lib/tasks/sessions.rake +9 -0
  191. data/lib/tasks/shops.rake +10 -0
  192. data/lib/tasks/start.rake +3 -0
  193. data/lib/tasks/webhooks.rake +10 -0
  194. data/test/controllers/disco_app/admin/shops_controller_test.rb +54 -0
  195. data/test/controllers/disco_app/charges_controller_test.rb +99 -0
  196. data/test/controllers/disco_app/install_controller_test.rb +50 -0
  197. data/test/controllers/disco_app/subscriptions_controller_test.rb +68 -0
  198. data/test/controllers/disco_app/webhooks_controller_test.rb +58 -0
  199. data/test/controllers/home_controller_test.rb +92 -0
  200. data/test/controllers/proxy_controller_test.rb +42 -0
  201. data/test/disco_app_test.rb +7 -0
  202. data/test/dummy/Rakefile +6 -0
  203. data/test/dummy/app/assets/javascripts/application.js +17 -0
  204. data/test/dummy/app/assets/stylesheets/application.scss +5 -0
  205. data/test/dummy/app/controllers/application_controller.rb +6 -0
  206. data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +8 -0
  207. data/test/dummy/app/controllers/home_controller.rb +7 -0
  208. data/test/dummy/app/controllers/proxy_controller.rb +8 -0
  209. data/test/dummy/app/helpers/application_helper.rb +2 -0
  210. data/test/dummy/app/jobs/disco_app/app_installed_job.rb +16 -0
  211. data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +11 -0
  212. data/test/dummy/app/jobs/products_create_job.rb +7 -0
  213. data/test/dummy/app/jobs/products_delete_job.rb +7 -0
  214. data/test/dummy/app/jobs/products_update_job.rb +7 -0
  215. data/test/dummy/app/models/disco_app/shop.rb +15 -0
  216. data/test/dummy/app/models/js_configuration.rb +8 -0
  217. data/test/dummy/app/models/product.rb +6 -0
  218. data/test/dummy/app/models/widget_configuration.rb +10 -0
  219. data/test/dummy/app/views/assets/script_tag.js.erb +1 -0
  220. data/test/dummy/app/views/assets/test.js.erb +1 -0
  221. data/test/dummy/app/views/assets/widget.js.erb +2 -0
  222. data/test/dummy/app/views/assets/widget.scss.erb +3 -0
  223. data/test/dummy/app/views/home/index.html.erb +2 -0
  224. data/test/dummy/bin/bundle +3 -0
  225. data/test/dummy/bin/rails +4 -0
  226. data/test/dummy/bin/rake +4 -0
  227. data/test/dummy/bin/setup +29 -0
  228. data/test/dummy/config/application.rb +38 -0
  229. data/test/dummy/config/boot.rb +5 -0
  230. data/test/dummy/config/database.codeship.yml +23 -0
  231. data/test/dummy/config/database.gitlab-ci.yml +24 -0
  232. data/test/dummy/config/database.yml +20 -0
  233. data/test/dummy/config/environment.rb +5 -0
  234. data/test/dummy/config/environments/development.rb +41 -0
  235. data/test/dummy/config/environments/production.rb +85 -0
  236. data/test/dummy/config/environments/test.rb +42 -0
  237. data/test/dummy/config/initializers/assets.rb +11 -0
  238. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  239. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  240. data/test/dummy/config/initializers/disco_app.rb +19 -0
  241. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  242. data/test/dummy/config/initializers/inflections.rb +16 -0
  243. data/test/dummy/config/initializers/mime_types.rb +4 -0
  244. data/test/dummy/config/initializers/omniauth.rb +9 -0
  245. data/test/dummy/config/initializers/session_store.rb +2 -0
  246. data/test/dummy/config/initializers/shopify_app.rb +7 -0
  247. data/test/dummy/config/initializers/shopify_session_repository.rb +7 -0
  248. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  249. data/test/dummy/config/locales/en.yml +23 -0
  250. data/test/dummy/config/routes.rb +10 -0
  251. data/test/dummy/config/secrets.yml +22 -0
  252. data/test/dummy/config.ru +4 -0
  253. data/test/dummy/db/migrate/20160307182229_create_products.rb +11 -0
  254. data/test/dummy/db/migrate/20160530160739_create_asset_models.rb +19 -0
  255. data/test/dummy/db/schema.rb +141 -0
  256. data/test/dummy/public/404.html +67 -0
  257. data/test/dummy/public/422.html +67 -0
  258. data/test/dummy/public/500.html +66 -0
  259. data/test/dummy/public/favicon.ico +0 -0
  260. data/test/fixtures/api/widget_store/assets/create_script_tag_js_request.json +6 -0
  261. data/test/fixtures/api/widget_store/assets/create_script_tag_js_response.json +12 -0
  262. data/test/fixtures/api/widget_store/assets/create_script_tag_request.json +6 -0
  263. data/test/fixtures/api/widget_store/assets/create_script_tag_response.json +10 -0
  264. data/test/fixtures/api/widget_store/assets/create_test_js_request.json +6 -0
  265. data/test/fixtures/api/widget_store/assets/create_test_js_response.json +12 -0
  266. data/test/fixtures/api/widget_store/assets/create_widget_js_request.json +6 -0
  267. data/test/fixtures/api/widget_store/assets/create_widget_js_response.json +12 -0
  268. data/test/fixtures/api/widget_store/assets/create_widget_scss_request.json +6 -0
  269. data/test/fixtures/api/widget_store/assets/create_widget_scss_response.json +12 -0
  270. data/test/fixtures/api/widget_store/assets/get_script_tags_empty_request.json +1 -0
  271. data/test/fixtures/api/widget_store/assets/get_script_tags_empty_response.json +1 -0
  272. data/test/fixtures/api/widget_store/assets/get_script_tags_preexisting_request.json +1 -0
  273. data/test/fixtures/api/widget_store/assets/get_script_tags_preexisting_response.json +12 -0
  274. data/test/fixtures/api/widget_store/assets/update_script_tag_request.json +10 -0
  275. data/test/fixtures/api/widget_store/assets/update_script_tag_response.json +10 -0
  276. data/test/fixtures/api/widget_store/charges/activate_application_charge_request.json +16 -0
  277. data/test/fixtures/api/widget_store/charges/activate_application_charge_response.json +1 -0
  278. data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_request.json +20 -0
  279. data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_response.json +1 -0
  280. data/test/fixtures/api/widget_store/charges/create_application_charge_request.json +9 -0
  281. data/test/fixtures/api/widget_store/charges/create_application_charge_response.json +16 -0
  282. data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_request.json +9 -0
  283. data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_response.json +20 -0
  284. data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_request.json +9 -0
  285. data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_response.json +20 -0
  286. data/test/fixtures/api/widget_store/charges/get_accepted_application_charge_response.json +16 -0
  287. data/test/fixtures/api/widget_store/charges/get_accepted_recurring_application_charge_response.json +20 -0
  288. data/test/fixtures/api/widget_store/charges/get_declined_application_charge_response.json +16 -0
  289. data/test/fixtures/api/widget_store/charges/get_declined_recurring_application_charge_response.json +20 -0
  290. data/test/fixtures/api/widget_store/charges/get_pending_application_charge_response.json +16 -0
  291. data/test/fixtures/api/widget_store/charges/get_pending_recurring_application_charge_response.json +20 -0
  292. data/test/fixtures/api/widget_store/shop.json +46 -0
  293. data/test/fixtures/api/widget_store/webhooks.json +1 -0
  294. data/test/fixtures/assets/test.js +1 -0
  295. data/test/fixtures/disco_app/application_charges.yml +11 -0
  296. data/test/fixtures/disco_app/plan_codes.yml +13 -0
  297. data/test/fixtures/disco_app/plans.yml +37 -0
  298. data/test/fixtures/disco_app/recurring_application_charges.yml +11 -0
  299. data/test/fixtures/disco_app/shops.yml +10 -0
  300. data/test/fixtures/disco_app/subscriptions.yml +22 -0
  301. data/test/fixtures/js_configurations.yml +3 -0
  302. data/test/fixtures/products.yml +4 -0
  303. data/test/fixtures/webhooks/app_uninstalled.json +46 -0
  304. data/test/fixtures/webhooks/product_created.json +167 -0
  305. data/test/fixtures/webhooks/product_deleted.json +3 -0
  306. data/test/fixtures/webhooks/product_updated.json +167 -0
  307. data/test/fixtures/widget_configurations.yml +4 -0
  308. data/test/integration/synchronises_test.rb +55 -0
  309. data/test/jobs/disco_app/app_installed_job_test.rb +55 -0
  310. data/test/jobs/disco_app/app_uninstalled_job_test.rb +30 -0
  311. data/test/models/disco_app/plan_test.rb +5 -0
  312. data/test/models/disco_app/renders_assets_test.rb +100 -0
  313. data/test/models/disco_app/session_test.rb +31 -0
  314. data/test/models/disco_app/shop_test.rb +27 -0
  315. data/test/models/disco_app/subscription_test.rb +19 -0
  316. data/test/services/disco_app/charges_service_test.rb +112 -0
  317. data/test/services/disco_app/subscription_service_test.rb +60 -0
  318. data/test/support/test_file_fixtures.rb +29 -0
  319. data/test/support/test_shopify_api.rb +16 -0
  320. data/test/test_helper.rb +55 -0
  321. metadata +798 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7b67b4667e899a379d0cc4152f228bfe7a80bef4aa6b35c26f54ee76c20c967f
4
+ data.tar.gz: d421b6283198d07e8ddc9a902e71a13320745e84f8fd5b3dbc981e6e88b70062
5
+ SHA512:
6
+ metadata.gz: b713f8e47aefe3614a2016bad8046d91fdee669fa5635f3768d167d9c6768622af51ec5f6cb711040f7d712dc2cdac2e9f879f4d752956c008444de52ad326ec
7
+ data.tar.gz: df1e8549d1e7474f137bc7d6a483f7e06450f26273181bdb4724b79003d6a3f51e19b4b29c6d0736f2f390e9d2c8dcd922d5b7e1785717166e70f6e152b4ebdd
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'DiscoApp'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><style>.st0{fill:#231F20;} .st1{fill:#FBAF41;} .st2{fill:#8676D5;} .st3{fill:#9CCC6B;} .st4{fill:#FBCC6B;} .st5{fill:#9CCCD5;} .st6{fill:#FFFFFF;}</style><path id="XMLID_7_" class="st0" d="M12 24l-5.2-3-5.2-3V6l5.2-3L12 0l5.2 3 5.2 3v12l-5.2 3-5.2 3z"/><path id="XMLID_6_" class="st1" d="M2.9 6.8v10.4h18.2z"/><path id="XMLID_5_" class="st2" d="M2.9 17.2h18.2V6.8z"/><path id="XMLID_4_" class="st3" d="M21.1 17.2L12 1.5 2.9 17.2z"/><path id="XMLID_3_" class="st4" d="M7.5 9.4l-4.6 7.8h18.2z"/><path id="XMLID_2_" class="st5" d="M2.9 17.2h18.2l-4.6-7.8z"/><path id="XMLID_1_" class="st6" d="M12 12l-9.1 5.2 9.1 5.3 9.1-5.3z"/></svg>
File without changes
@@ -0,0 +1,61 @@
1
+ var FilterableShopList = React.createClass({
2
+
3
+ getDefaultProps: function() {
4
+ return {
5
+ filterTabs: [
6
+ { label: 'All Shops', filter: {} },
7
+ { label: 'Installed', filter: { 'filter[status]': 'installed' } },
8
+ { label: 'Uninstalled', filter: { 'filter[status]': 'uninstalled' } }
9
+ ],
10
+ availableFilters: {
11
+ 'filter[status]': {
12
+ getLabel: function(value) {
13
+ return 'Status is ' + value;
14
+ }
15
+ }
16
+ }
17
+ }
18
+ },
19
+
20
+ getInitialState: function() {
21
+ return {
22
+ filter: {}
23
+ };
24
+ },
25
+
26
+ onFilterReplace: function(filter) {
27
+ this.setState({
28
+ filter: filter
29
+ });
30
+ },
31
+
32
+ onFilterSet: function(name, value) {
33
+ this.onFiltersSet([{
34
+ name: name,
35
+ value: value
36
+ }]);
37
+ },
38
+
39
+ onFiltersSet: function(filters) {
40
+ var nextFilter = $.extend({}, this.state.filter);
41
+ filters.forEach(function(filter) {
42
+ if(!filter.value) {
43
+ delete nextFilter[filter.name];
44
+ } else {
45
+ nextFilter[filter.name] = filter.value;
46
+ }
47
+ });
48
+ this.onFilterReplace(nextFilter);
49
+ },
50
+
51
+ render: function() {
52
+ return (
53
+ <div className="next-card">
54
+ <ShopFilterTabs filterTabs={this.props.filterTabs} filter={this.state.filter} onFilterReplace={this.onFilterReplace} />
55
+ <ShopFilterQuery filter={this.state.filter} onFilterSet={this.onFilterSet} />
56
+ <ShopList shopsUrl={this.props.shopsUrl} editShopUrl={this.props.editShopUrl} editSubscriptionUrl={this.props.editSubscriptionUrl} filter={this.state.filter} />
57
+ </div>
58
+ );
59
+ }
60
+
61
+ });
@@ -0,0 +1,59 @@
1
+ class InlineRadioOptions extends React.Component {
2
+
3
+ constructor(props) {
4
+ super(props);
5
+ this.state = {
6
+ value: props.value
7
+ }
8
+ }
9
+
10
+ onChange(value) {
11
+ this.setState({
12
+ value: value
13
+ })
14
+ }
15
+
16
+ render() {
17
+ const { name, label, options } = this.props;
18
+
19
+ const optionElements = options.map((option, optionIndex) => {
20
+ return (
21
+ <InputRadio
22
+ key={option.value}
23
+ name={name}
24
+ value={option.value}
25
+ label={option.label}
26
+ inline={true}
27
+ isLast={optionIndex === (options.length - 1)}
28
+ checked={option.value === this.state.value}
29
+ onChange={this.onChange.bind(this)}
30
+ />
31
+ );
32
+ });
33
+
34
+ return (
35
+ <CardSection wrappable={true}>
36
+ <div className="wrappable__item wrappable__item--no-flex">
37
+ <span>{label}</span>
38
+ </div>
39
+ <div className="wrappable__item">
40
+ {optionElements}
41
+ </div>
42
+ </CardSection>
43
+ );
44
+ }
45
+
46
+ }
47
+
48
+ InlineRadioOptions.propTypes = {
49
+ name: React.PropTypes.string,
50
+ options: React.PropTypes.arrayOf(
51
+ React.PropTypes.shape({
52
+ label: React.PropTypes.string.isRequired,
53
+ value: React.PropTypes.oneOfType([
54
+ React.PropTypes.string,
55
+ React.PropTypes.bool
56
+ ]).isRequired
57
+ })
58
+ ).isRequired
59
+ };
@@ -0,0 +1,417 @@
1
+ /**
2
+ * Defines a generic RulesEditor class. This class can't be used directly, but
3
+ * should be inherited, with the inheriting class defining a list of column
4
+ * types and corresponding relations and condition data types, like so:
5
+ *
6
+ * class MyRulesEditor extends RulesEditor {};
7
+ * MyRulesEditor.defaultProps = {
8
+ * columns: {
9
+ * title: {
10
+ * label: 'Product title',
11
+ * column: 'title',
12
+ * relations: RulesEditor.buildRelationsObj([RulesEditor.EQUALS_STRING])
13
+ * }
14
+ * }
15
+ */
16
+ class RulesEditor extends React.Component {
17
+
18
+ /**
19
+ * Initialise the Rules Editor, and set the initial state.
20
+ * @param props
21
+ */
22
+ constructor(props) {
23
+ super(props);
24
+ this.state = {
25
+ rules: props.rules.map((rule, i) => {
26
+ return Object.assign({}, rule, {
27
+ column: Object.keys(this.props.columns).filter((columnKey) => {
28
+ return this.props.columns[columnKey].column == rule.column;
29
+ })[0]
30
+ });
31
+ })
32
+ }
33
+ }
34
+
35
+ componentDidMount() {
36
+ if(this.state.rules.length === 0 && this.props.blankOk === false) {
37
+ this.onAddRule();
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Add a new rule, with an immutable state change.
43
+ */
44
+ onAddRule() {
45
+ const column = Object.keys(this.props.columns)[0];
46
+ const relation = this.getNextRelation(column);
47
+ const condition = this.getNextCondition(column, relation);
48
+
49
+ this.setState({
50
+ rules: this.state.rules.concat([{
51
+ column,
52
+ relation,
53
+ condition
54
+ }])
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Remove a rule, with an immutable state change.
60
+ */
61
+ onRemoveRule(index) {
62
+ this.setState({
63
+ rules: [
64
+ ...this.state.rules.slice(0, index),
65
+ ...this.state.rules.slice(index + 1)
66
+ ]
67
+ });
68
+ }
69
+
70
+ /**
71
+ * Handle a change in a rule's column attribute.
72
+ *
73
+ * @param index
74
+ * @param column
75
+ */
76
+ onRuleColumnChange(index, column) {
77
+ const relation = this.getNextRelation(column, this.state.rules[index]);
78
+ const condition = this.getNextCondition(column, relation, this.state.rules[index]);
79
+
80
+ this.updateRule(index, {
81
+ column,
82
+ relation,
83
+ condition
84
+ })
85
+ }
86
+
87
+ /**
88
+ * Handle a change in a rule's relation attribute.
89
+ *
90
+ * @param index
91
+ * @param relation
92
+ */
93
+ onRuleRelationChange(index, relation) {
94
+ const condition = this.getNextCondition(this.state.rules[index].column, relation, this.state.rules[index]);
95
+
96
+ this.updateRule(index, {
97
+ relation,
98
+ condition
99
+ });
100
+ }
101
+
102
+ /**
103
+ * Handle a change in a rule's condition attribute.
104
+ *
105
+ * @param index
106
+ * @param condition
107
+ */
108
+ onRuleConditionChange(index, condition) {
109
+ this.updateRule(index, {
110
+ condition
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Handle a change in a rule's variables
116
+ *
117
+ * @param index
118
+ * @param name
119
+ * @param value
120
+ */
121
+ onRuleVariableChange(index, name, value) {
122
+ this.updateRule(index, {
123
+ [name]: value
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Given the column we're changing to and the current rule, return the next
129
+ * relation value.
130
+ *
131
+ * @param nextColumn
132
+ * @param currentRule
133
+ */
134
+ getNextRelation(nextColumn, currentRule) {
135
+ // If the new column provides for the same relation, keep it.
136
+ if(currentRule && (this.props.columns[nextColumn].relations[currentRule.relation] !== undefined)) {
137
+ return currentRule.relation;
138
+ }
139
+ // Otherwise, return the first relation for the new column.
140
+ return Object.keys(this.props.columns[nextColumn].relations)[0];
141
+ }
142
+
143
+ /**
144
+ * Given the column and relation we're changing to and the current condition,
145
+ * return the value that the condition should be changed to.
146
+ *
147
+ * @param nextColumn
148
+ * @param nextRelation
149
+ * @param currentRule
150
+ */
151
+ getNextCondition(nextColumn, nextRelation, currentRule) {
152
+ // If the new relation provides for the same condition type, keep it.
153
+ if(currentRule) {
154
+ const currentConditionType = this.props.columns[currentRule.column].relations[currentRule.relation].type;
155
+ const nextConditionType = this.props.columns[nextColumn].relations[nextRelation].type;
156
+
157
+ if(currentConditionType === nextConditionType) {
158
+ return currentRule.condition;
159
+ }
160
+ }
161
+
162
+ // Otherwise, reset the condition to an empty string.
163
+ return '';
164
+ }
165
+
166
+ /**
167
+ * Handle the updating of a rule in our array in an immutable manner.
168
+ *
169
+ * @param index
170
+ * @param updates
171
+ */
172
+ updateRule(index, updates) {
173
+ let updatedRule = Object.assign({}, this.state.rules[index], updates);
174
+
175
+ // Ensure only valid variables are present in the rule
176
+ const columnPath = this.props.columns[updatedRule.column].column;
177
+ const columnVariables = RulesEditor.getColumnPathVariables(columnPath);
178
+ Object.keys(updatedRule).forEach(function (key) {
179
+ if ('$' === key[0] && -1 === columnVariables.indexOf(key)) {
180
+ delete updatedRule[key];
181
+ }
182
+ });
183
+
184
+ this.setState({
185
+ rules: [
186
+ ...this.state.rules.slice(0, index),
187
+ updatedRule,
188
+ ...this.state.rules.slice(index + 1)
189
+ ]
190
+ });
191
+ }
192
+
193
+ /**
194
+ * Render the Rules Editor.
195
+ */
196
+ render() {
197
+ const { name } = this.props;
198
+ const { rules } = this.state;
199
+
200
+ const ruleElements = rules.map((rule, i) => {
201
+ return <RulesEditorRule
202
+ key={i}
203
+ rule={rule}
204
+ columns={this.props.columns}
205
+ onRemove={this.onRemoveRule.bind(this, i)}
206
+ onColumnChange={this.onRuleColumnChange.bind(this, i)}
207
+ onRelationChange={this.onRuleRelationChange.bind(this, i)}
208
+ onConditionChange={this.onRuleConditionChange.bind(this, i)}
209
+ onVariableChange={this.onRuleVariableChange.bind(this, i)}
210
+ ruleCount={rules.length}
211
+ blankOk = {this.props.blankOk}
212
+ />
213
+ });
214
+
215
+ // Convert the current rules JSON into a format using the correct column
216
+ // format used by our more advanced key checker.
217
+ const rulesJSON = JSON.stringify(this.state.rules.map((rule, i) => {
218
+ return Object.assign({}, rule, {
219
+ column: this.props.columns[rule.column].column
220
+ });
221
+ }));
222
+
223
+ return(
224
+ <CardSection>
225
+ <div className="next-grid next-grid--no-outside-padding">
226
+ <div style={{ width: '100%'}}>
227
+ {ruleElements}
228
+ </div>
229
+ </div>
230
+ <Button onClick={this.onAddRule.bind(this)}>
231
+ Add another condition
232
+ </Button>
233
+ <input type="hidden" name={name} value={rulesJSON} />
234
+ </CardSection>
235
+ );
236
+ }
237
+
238
+ /**
239
+ * Get the variable names present in a column definition
240
+ *
241
+ * @param column
242
+ * @returns {Array.<String>}
243
+ */
244
+ static getColumnPathVariables(column) {
245
+ return column.split(/[^$a-z_A-Z]/).filter((key) => '$' === key[0]);
246
+ }
247
+
248
+ /**
249
+ * Return a relations object, which is just the passed array
250
+ * turned into an object which is keyed by the `relation` value
251
+ *
252
+ * @param relations
253
+ * @returns {{}}
254
+ */
255
+ static buildRelationsObj(relations) {
256
+ var relationsObj = {};
257
+
258
+ relations.forEach(function (relation) {
259
+ return relationsObj[relation.relation] = relation;
260
+ });
261
+
262
+ return relationsObj;
263
+ }
264
+
265
+ }
266
+
267
+
268
+ RulesEditor.EQUALS_STRING = {
269
+ label: 'is equal to',
270
+ relation: 'is_equal_to',
271
+ type: 'text'
272
+ };
273
+ RulesEditor.EQUALS_COUNTRY_CODE = {
274
+ label: 'is equal to',
275
+ relation: 'is_equal_to',
276
+ type: 'country_code'
277
+ };
278
+ RulesEditor.CONTAINS_STRING = {
279
+ label: 'contains',
280
+ relation: 'contains_string',
281
+ type: 'text'
282
+ };
283
+ RulesEditor.EQUALS_TAG = {
284
+ label: 'is equal to',
285
+ relation: 'find_in_set',
286
+ type: 'tag'
287
+ };
288
+ RulesEditor.GREATER_THAN = {
289
+ label: 'is greater than',
290
+ relation: 'is_greater_than',
291
+ type: 'numeric'
292
+ };
293
+ RulesEditor.LESS_THAN = {
294
+ label: 'is less than',
295
+ relation: 'is_less_than',
296
+ type: 'numeric'
297
+ };
298
+
299
+ const RulesEditorRule = ({ rule, columns, onRemove, onColumnChange, onVariableChange, onRelationChange, onConditionChange, ruleCount, blankOk }) => {
300
+ const { column, relation, condition } = rule;
301
+
302
+ const currentColumn = columns[column];
303
+ const currentRelation = currentColumn.relations[relation];
304
+
305
+ let conditionEditor = null;
306
+ switch(currentRelation.type) {
307
+ case 'text':
308
+ case 'numeric':
309
+ case 'tag':
310
+ conditionEditor = <RulesEditorConditionInputText condition={condition} onChange={onConditionChange} />;
311
+ break;
312
+ case 'country_code':
313
+ conditionEditor = <RulesEditorConditionInputCountryCode condition={condition} onChange={onConditionChange} />;
314
+ break;
315
+ }
316
+
317
+ let deleteIconCell = null;
318
+ if(ruleCount > 1 || blankOk === true) {
319
+ deleteIconCell = (
320
+ <div className="sl">
321
+ <button type="button" className="btn btn--icon" onClick={onRemove}>
322
+ <i className="ico ico-14-svg ico-delete" />
323
+ </button>
324
+ </div>
325
+ );
326
+ }
327
+
328
+ const columnVariables = RulesEditor.getColumnPathVariables(currentColumn.column);
329
+
330
+ let variablesEditor = columnVariables.map(function(name) {
331
+ return (
332
+ <div className="next-grid__cell" key={name}>
333
+ <RulesEditorVariableInput name={name} value={rule[name]} onChange={onVariableChange.bind(this, name)} />
334
+ </div>
335
+ );
336
+ });
337
+
338
+ return (
339
+ <div>
340
+ <div className="next-grid next-grid--no-padding next-grid--compact">
341
+ <div className="next-grid__cell">
342
+ <div className="next-grid next-grid--compact next-grid--no-outside-padding">
343
+ <div className="next-grid__cell">
344
+ <RulesEditorColumnSelect currentColumnName={column} columns={columns} onChange={onColumnChange} />
345
+ </div>
346
+ {variablesEditor}
347
+ <div className="next-grid__cell">
348
+ <RulesEditorRelationSelect currentRelationName={relation} relations={currentColumn.relations} onChange={onRelationChange} />
349
+ </div>
350
+ <div className="next-grid__cell">
351
+ {conditionEditor}
352
+ </div>
353
+ </div>
354
+ </div>
355
+ {deleteIconCell}
356
+ </div>
357
+ <hr className="next-card__section__separator" />
358
+ </div>
359
+ );
360
+
361
+ };
362
+
363
+ const RulesEditorColumnSelect = ({ currentColumnName, columns, onChange }) => {
364
+ const options = Object.keys(columns).map((columnName) => {
365
+ return { label: columns[columnName].label, value: columnName }
366
+ });
367
+
368
+ return <InputSelect options={options} value={currentColumnName} onChange={onChange} label="Field" labelHidden={true} />;
369
+ };
370
+
371
+ const RulesEditorVariableInput = ({ name, value, onChange }) => {
372
+
373
+ const handleChange = (e) => {
374
+ onChange && onChange(e);
375
+ };
376
+
377
+ let label = name.substr(1).trim().replace( /([A-Z])/g, " $1" );
378
+ label = label.charAt(0).toUpperCase() + label.substr(1);
379
+
380
+ return (
381
+ <InputText value={value} onChange={handleChange} label={label} labelHidden={true} placeholder={label} required={true} />
382
+ );
383
+ };
384
+
385
+ const RulesEditorRelationSelect = ({ currentRelationName, relations, onChange }) => {
386
+ const options = Object.keys(relations).map((relationName) => {
387
+ return { label: relations[relationName].label, value: relationName }
388
+ });
389
+
390
+ return <InputSelect options={options} value={currentRelationName} onChange={onChange} label="Relation" labelHidden={true} />;
391
+ };
392
+
393
+ const RulesEditorConditionInputText = ({ condition, onChange }) => {
394
+
395
+ const handleChange = (e) => {
396
+ onChange && onChange(e);
397
+ };
398
+
399
+ return (
400
+ <InputText value={condition} onChange={handleChange} label="Value" labelHidden={true} />
401
+ );
402
+
403
+ };
404
+
405
+ const RulesEditorConditionInputCountryCode = ({ condition, onChange }) => {
406
+
407
+ const handleChange = (e) => {
408
+ onChange && onChange(e);
409
+ };
410
+
411
+ const countryOptions = [{"label":"Australia","value":"AU"},{"label":"Canada","value":"CA"},{"label":"United Kingdom","value":"GB"},{"label":"United States","value":"US"},{"label":"Afghanistan","value":"AF"},{"label":"Åland Islands","value":"AX"},{"label":"Albania","value":"AL"},{"label":"Algeria","value":"DZ"},{"label":"Andorra","value":"AD"},{"label":"Angola","value":"AO"},{"label":"Anguilla","value":"AI"},{"label":"Antigua & Barbuda","value":"AG"},{"label":"Argentina","value":"AR"},{"label":"Armenia","value":"AM"},{"label":"Aruba","value":"AW"},{"label":"Australia","value":"AU"},{"label":"Austria","value":"AT"},{"label":"Azerbaijan","value":"AZ"},{"label":"Bahamas","value":"BS"},{"label":"Bahrain","value":"BH"},{"label":"Bangladesh","value":"BD"},{"label":"Barbados","value":"BB"},{"label":"Belarus","value":"BY"},{"label":"Belgium","value":"BE"},{"label":"Belize","value":"BZ"},{"label":"Benin","value":"BJ"},{"label":"Bermuda","value":"BM"},{"label":"Bhutan","value":"BT"},{"label":"Bolivia","value":"BO"},{"label":"Bosnia & Herzegovina","value":"BA"},{"label":"Botswana","value":"BW"},{"label":"Bouvet Island","value":"BV"},{"label":"Brazil","value":"BR"},{"label":"British Indian Ocean Territory","value":"IO"},{"label":"British Virgin Islands","value":"VG"},{"label":"Brunei","value":"BN"},{"label":"Bulgaria","value":"BG"},{"label":"Burkina Faso","value":"BF"},{"label":"Burundi","value":"BI"},{"label":"Cambodia","value":"KH"},{"label":"Cameroon","value":"CM"},{"label":"Canada","value":"CA"},{"label":"Cape Verde","value":"CV"},{"label":"Cayman Islands","value":"KY"},{"label":"Central African Republic","value":"CF"},{"label":"Chad","value":"TD"},{"label":"Chile","value":"CL"},{"label":"China","value":"CN"},{"label":"Christmas Island","value":"CX"},{"label":"Cocos (Keeling) Islands","value":"CC"},{"label":"Colombia","value":"CO"},{"label":"Comoros","value":"KM"},{"label":"Congo - Brazzaville","value":"CG"},{"label":"Congo - Kinshasa","value":"CD"},{"label":"Cook Islands","value":"CK"},{"label":"Costa Rica","value":"CR"},{"label":"Croatia","value":"HR"},{"label":"Cuba","value":"CU"},{"label":"Curaçao","value":"CW"},{"label":"Cyprus","value":"CY"},{"label":"Czech Republic","value":"CZ"},{"label":"Côte d’Ivoire","value":"CI"},{"label":"Denmark","value":"DK"},{"label":"Djibouti","value":"DJ"},{"label":"Dominica","value":"DM"},{"label":"Dominican Republic","value":"DO"},{"label":"Ecuador","value":"EC"},{"label":"Egypt","value":"EG"},{"label":"El Salvador","value":"SV"},{"label":"Equatorial Guinea","value":"GQ"},{"label":"Eritrea","value":"ER"},{"label":"Estonia","value":"EE"},{"label":"Ethiopia","value":"ET"},{"label":"Falkland Islands","value":"FK"},{"label":"Faroe Islands","value":"FO"},{"label":"Fiji","value":"FJ"},{"label":"Finland","value":"FI"},{"label":"France","value":"FR"},{"label":"French Guiana","value":"GF"},{"label":"French Polynesia","value":"PF"},{"label":"French Southern Territories","value":"TF"},{"label":"Gabon","value":"GA"},{"label":"Gambia","value":"GM"},{"label":"Georgia","value":"GE"},{"label":"Germany","value":"DE"},{"label":"Ghana","value":"GH"},{"label":"Gibraltar","value":"GI"},{"label":"Greece","value":"GR"},{"label":"Greenland","value":"GL"},{"label":"Grenada","value":"GD"},{"label":"Guadeloupe","value":"GP"},{"label":"Guatemala","value":"GT"},{"label":"Guernsey","value":"GG"},{"label":"Guinea","value":"GN"},{"label":"Guinea-Bissau","value":"GW"},{"label":"Guyana","value":"GY"},{"label":"Haiti","value":"HT"},{"label":"Heard & McDonald Islands","value":"HM"},{"label":"Honduras","value":"HN"},{"label":"Hong Kong SAR China","value":"HK"},{"label":"Hungary","value":"HU"},{"label":"Iceland","value":"IS"},{"label":"India","value":"IN"},{"label":"Indonesia","value":"ID"},{"label":"Iran","value":"IR"},{"label":"Iraq","value":"IQ"},{"label":"Ireland","value":"IE"},{"label":"Isle of Man","value":"IM"},{"label":"Israel","value":"IL"},{"label":"Italy","value":"IT"},{"label":"Jamaica","value":"JM"},{"label":"Japan","value":"JP"},{"label":"Jersey","value":"JE"},{"label":"Jordan","value":"JO"},{"label":"Kazakhstan","value":"KZ"},{"label":"Kenya","value":"KE"},{"label":"Kiribati","value":"KI"},{"label":"Kosovo","value":"KV"},{"label":"Kuwait","value":"KW"},{"label":"Kyrgyzstan","value":"KG"},{"label":"Laos","value":"LA"},{"label":"Latvia","value":"LV"},{"label":"Lebanon","value":"LB"},{"label":"Lesotho","value":"LS"},{"label":"Liberia","value":"LR"},{"label":"Libya","value":"LY"},{"label":"Liechtenstein","value":"LI"},{"label":"Lithuania","value":"LT"},{"label":"Luxembourg","value":"LU"},{"label":"Macau SAR China","value":"MO"},{"label":"Macedonia","value":"MK"},{"label":"Madagascar","value":"MG"},{"label":"Malawi","value":"MW"},{"label":"Malaysia","value":"MY"},{"label":"Maldives","value":"MV"},{"label":"Mali","value":"ML"},{"label":"Malta","value":"MT"},{"label":"Martinique","value":"MQ"},{"label":"Mauritania","value":"MR"},{"label":"Mauritius","value":"MU"},{"label":"Mayotte","value":"YT"},{"label":"Mexico","value":"MX"},{"label":"Moldova","value":"MD"},{"label":"Monaco","value":"MC"},{"label":"Mongolia","value":"MN"},{"label":"Montenegro","value":"ME"},{"label":"Montserrat","value":"MS"},{"label":"Morocco","value":"MA"},{"label":"Mozambique","value":"MZ"},{"label":"Myanmar (Burma)","value":"MM"},{"label":"Namibia","value":"NA"},{"label":"Nauru","value":"NR"},{"label":"Nepal","value":"NP"},{"label":"Netherlands","value":"NL"},{"label":"Netherlands Antilles","value":"AN"},{"label":"New Caledonia","value":"NC"},{"label":"New Zealand","value":"NZ"},{"label":"Nicaragua","value":"NI"},{"label":"Niger","value":"NE"},{"label":"Nigeria","value":"NG"},{"label":"Niue","value":"NU"},{"label":"Norfolk Island","value":"NF"},{"label":"North Korea","value":"KP"},{"label":"Norway","value":"NO"},{"label":"Oman","value":"OM"},{"label":"Pakistan","value":"PK"},{"label":"Palestinian Territories","value":"PS"},{"label":"Panama","value":"PA"},{"label":"Papua New Guinea","value":"PG"},{"label":"Paraguay","value":"PY"},{"label":"Peru","value":"PE"},{"label":"Philippines","value":"PH"},{"label":"Pitcairn Islands","value":"PN"},{"label":"Poland","value":"PL"},{"label":"Portugal","value":"PT"},{"label":"Qatar","value":"QA"},{"label":"Réunion","value":"RE"},{"label":"Romania","value":"RO"},{"label":"Russia","value":"RU"},{"label":"Rwanda","value":"RW"},{"label":"Samoa","value":"WS"},{"label":"San Marino","value":"SM"},{"label":"São Tomé & Príncipe","value":"ST"},{"label":"Saudi Arabia","value":"SA"},{"label":"Senegal","value":"SN"},{"label":"Serbia","value":"RS"},{"label":"Seychelles","value":"SC"},{"label":"Sierra Leone","value":"SL"},{"label":"Singapore","value":"SG"},{"label":"Sint Maarten","value":"SX"},{"label":"Slovakia","value":"SK"},{"label":"Slovenia","value":"SI"},{"label":"Solomon Islands","value":"SB"},{"label":"Somalia","value":"SO"},{"label":"South Africa","value":"ZA"},{"label":"South Georgia & South Sandwich Islands","value":"GS"},{"label":"South Korea","value":"KR"},{"label":"Spain","value":"ES"},{"label":"Sri Lanka","value":"LK"},{"label":"St. Barthélemy","value":"BL"},{"label":"St. Helena","value":"SH"},{"label":"St. Kitts & Nevis","value":"KN"},{"label":"St. Lucia","value":"LC"},{"label":"St. Martin","value":"MF"},{"label":"St. Pierre & Miquelon","value":"PM"},{"label":"St. Vincent & Grenadines","value":"VC"},{"label":"Sudan","value":"SD"},{"label":"Suriname","value":"SR"},{"label":"Svalbard & Jan Mayen","value":"SJ"},{"label":"Swaziland","value":"SZ"},{"label":"Sweden","value":"SE"},{"label":"Switzerland","value":"CH"},{"label":"Syria","value":"SY"},{"label":"Taiwan","value":"TW"},{"label":"Tajikistan","value":"TJ"},{"label":"Tanzania","value":"TZ"},{"label":"Thailand","value":"TH"},{"label":"Timor-Leste","value":"TL"},{"label":"Togo","value":"TG"},{"label":"Tokelau","value":"TK"},{"label":"Tonga","value":"TO"},{"label":"Trinidad & Tobago","value":"TT"},{"label":"Tunisia","value":"TN"},{"label":"Turkey","value":"TR"},{"label":"Turkmenistan","value":"TM"},{"label":"Turks & Caicos Islands","value":"TC"},{"label":"Tuvalu","value":"TV"},{"label":"U.S. Outlying Islands","value":"UM"},{"label":"Uganda","value":"UG"},{"label":"Ukraine","value":"UA"},{"label":"United Arab Emirates","value":"AE"},{"label":"United Kingdom","value":"GB"},{"label":"United States","value":"US"},{"label":"Uruguay","value":"UY"},{"label":"Uzbekistan","value":"UZ"},{"label":"Vanuatu","value":"VU"},{"label":"Vatican City","value":"VA"},{"label":"Venezuela","value":"VE"},{"label":"Vietnam","value":"VN"},{"label":"Wallis & Futuna","value":"WF"},{"label":"Western Sahara","value":"EH"},{"label":"Yemen","value":"YE"},{"label":"Zambia","value":"ZM"},{"label":"Zimbabwe","value":"ZW"}];
412
+
413
+ return (
414
+ <InputSelect options={countryOptions} value={condition} onChange={handleChange} label="Value" labelHidden={true} />
415
+ );
416
+
417
+ };
@@ -0,0 +1,13 @@
1
+ const ShopFilterQuery = ({ filter, onFilterSet }) => {
2
+
3
+ const onChange = (value) => {
4
+ onFilterSet('filter[query]', value);
5
+ };
6
+
7
+ return (
8
+ <CardSection>
9
+ <InputText label="Search" placeholder="Start typing to search for stores..." labelHidden={true} value={filter.query} onChange={onChange} />
10
+ </CardSection>
11
+ );
12
+
13
+ };
@@ -0,0 +1,34 @@
1
+ var ShopFilterTab = React.createClass({
2
+
3
+ /**
4
+ * Handle a click event on the individual tab link.
5
+ * @param e
6
+ */
7
+ handleClick: function(e) {
8
+ e.preventDefault();
9
+
10
+ // Don't do anything if this is already the currently selected tab.
11
+ if(this.isActive()) return;
12
+
13
+ this.props.onFilterTabSelected(this.props.filterTab);
14
+ },
15
+
16
+ /**
17
+ * Return true if this is the currently active tab, determined by whether the filter values for this tab match the
18
+ * currently active filter.
19
+ * @returns {boolean}
20
+ */
21
+ isActive: function() {
22
+ return (JSON.stringify(this.props.filterTab.filter) == JSON.stringify(this.props.filter));
23
+ },
24
+
25
+ render: function() {
26
+ var tabClassName = this.isActive() ? 'next-tab next-tab--is-active' : 'next-tab';
27
+ return (
28
+ <li role="presentation">
29
+ <a href="#" className={tabClassName} onClick={this.handleClick}>{this.props.filterTab.label}</a>
30
+ </li>
31
+ )
32
+ }
33
+
34
+ });