disco_app 0.8.8

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 (254) 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/javascripts/disco_app/components/filterable_shop_list.js.jsx +65 -0
  5. data/app/assets/javascripts/disco_app/components/shop_filter_tab.js.jsx +34 -0
  6. data/app/assets/javascripts/disco_app/components/shop_filter_tabs.js.jsx +21 -0
  7. data/app/assets/javascripts/disco_app/components/shop_list.js.jsx +140 -0
  8. data/app/assets/javascripts/disco_app/components/shop_row.js.jsx +27 -0
  9. data/app/assets/javascripts/disco_app/components/shopify_admin_link.js.jsx +29 -0
  10. data/app/assets/javascripts/disco_app/components.js +5 -0
  11. data/app/assets/javascripts/disco_app/disco_app.js +7 -0
  12. data/app/assets/javascripts/disco_app/frame.js +152 -0
  13. data/app/assets/javascripts/disco_app/shopify-turbolinks.js +7 -0
  14. data/app/assets/stylesheets/disco_app/bootstrap/_custom.scss +54 -0
  15. data/app/assets/stylesheets/disco_app/bootstrap/_variables.scss +872 -0
  16. data/app/assets/stylesheets/disco_app/disco/_buttons.scss +31 -0
  17. data/app/assets/stylesheets/disco_app/disco/_cards.scss +51 -0
  18. data/app/assets/stylesheets/disco_app/disco/_forms.scss +23 -0
  19. data/app/assets/stylesheets/disco_app/disco/_grid.scss +58 -0
  20. data/app/assets/stylesheets/disco_app/disco/_sections.scss +61 -0
  21. data/app/assets/stylesheets/disco_app/disco/_tables.scss +57 -0
  22. data/app/assets/stylesheets/disco_app/disco/_tabs.scss +61 -0
  23. data/app/assets/stylesheets/disco_app/disco/_type.scss +39 -0
  24. data/app/assets/stylesheets/disco_app/disco/mixins/_flexbox.scss +394 -0
  25. data/app/assets/stylesheets/disco_app/disco_app.scss +16 -0
  26. data/app/assets/stylesheets/disco_app/frame/_buttons.scss +54 -0
  27. data/app/assets/stylesheets/disco_app/frame/_forms.scss +26 -0
  28. data/app/assets/stylesheets/disco_app/frame/_layout.scss +77 -0
  29. data/app/assets/stylesheets/disco_app/frame/_type.scss +32 -0
  30. data/app/assets/stylesheets/disco_app/frame.scss +9 -0
  31. data/app/controllers/disco_app/admin/app_settings_controller.rb +3 -0
  32. data/app/controllers/disco_app/admin/application_controller.rb +3 -0
  33. data/app/controllers/disco_app/admin/concerns/app_settings_controller.rb +24 -0
  34. data/app/controllers/disco_app/admin/concerns/authenticated_controller.rb +20 -0
  35. data/app/controllers/disco_app/admin/concerns/plans_controller.rb +51 -0
  36. data/app/controllers/disco_app/admin/concerns/shops_controller.rb +7 -0
  37. data/app/controllers/disco_app/admin/plans_controller.rb +3 -0
  38. data/app/controllers/disco_app/admin/resources/shops_controller.rb +3 -0
  39. data/app/controllers/disco_app/admin/shops_controller.rb +3 -0
  40. data/app/controllers/disco_app/charges_controller.rb +47 -0
  41. data/app/controllers/disco_app/concerns/app_proxy_controller.rb +40 -0
  42. data/app/controllers/disco_app/concerns/authenticated_controller.rb +56 -0
  43. data/app/controllers/disco_app/concerns/carrier_request_controller.rb +21 -0
  44. data/app/controllers/disco_app/frame_controller.rb +9 -0
  45. data/app/controllers/disco_app/install_controller.rb +27 -0
  46. data/app/controllers/disco_app/subscriptions_controller.rb +40 -0
  47. data/app/controllers/disco_app/webhooks_controller.rb +46 -0
  48. data/app/controllers/sessions_controller.rb +22 -0
  49. data/app/helpers/disco_app/application_helper.rb +28 -0
  50. data/app/jobs/disco_app/app_installed_job.rb +3 -0
  51. data/app/jobs/disco_app/app_uninstalled_job.rb +3 -0
  52. data/app/jobs/disco_app/concerns/app_installed_job.rb +39 -0
  53. data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +20 -0
  54. data/app/jobs/disco_app/concerns/shop_update_job.rb +16 -0
  55. data/app/jobs/disco_app/concerns/subscription_changed_job.rb +7 -0
  56. data/app/jobs/disco_app/concerns/synchronise_carrier_service_job.rb +52 -0
  57. data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +61 -0
  58. data/app/jobs/disco_app/shop_job.rb +27 -0
  59. data/app/jobs/disco_app/shop_update_job.rb +3 -0
  60. data/app/jobs/disco_app/subscription_changed_job.rb +3 -0
  61. data/app/jobs/disco_app/synchronise_carrier_service_job.rb +3 -0
  62. data/app/jobs/disco_app/synchronise_webhooks_job.rb +3 -0
  63. data/app/models/disco_app/app_settings.rb +3 -0
  64. data/app/models/disco_app/application_charge.rb +18 -0
  65. data/app/models/disco_app/concerns/app_settings.rb +7 -0
  66. data/app/models/disco_app/concerns/plan.rb +26 -0
  67. data/app/models/disco_app/concerns/plan_code.rb +15 -0
  68. data/app/models/disco_app/concerns/shop.rb +76 -0
  69. data/app/models/disco_app/concerns/subscription.rb +48 -0
  70. data/app/models/disco_app/concerns/synchronises.rb +39 -0
  71. data/app/models/disco_app/plan.rb +3 -0
  72. data/app/models/disco_app/plan_code.rb +3 -0
  73. data/app/models/disco_app/recurring_application_charge.rb +18 -0
  74. data/app/models/disco_app/session_storage.rb +18 -0
  75. data/app/models/disco_app/shop.rb +3 -0
  76. data/app/models/disco_app/subscription.rb +3 -0
  77. data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +46 -0
  78. data/app/resources/disco_app/admin/resources/shop_resource.rb +4 -0
  79. data/app/services/disco_app/carrier_request_service.rb +15 -0
  80. data/app/services/disco_app/charges_service.rb +81 -0
  81. data/app/services/disco_app/proxy_service.rb +17 -0
  82. data/app/services/disco_app/subscription_service.rb +37 -0
  83. data/app/services/disco_app/webhook_service.rb +30 -0
  84. data/app/views/disco_app/admin/app_settings/edit.html.erb +5 -0
  85. data/app/views/disco_app/admin/plans/_form.html.erb +27 -0
  86. data/app/views/disco_app/admin/plans/edit.html.erb +7 -0
  87. data/app/views/disco_app/admin/plans/index.html.erb +32 -0
  88. data/app/views/disco_app/admin/plans/new.html.erb +7 -0
  89. data/app/views/disco_app/admin/shops/index.html.erb +12 -0
  90. data/app/views/disco_app/charges/activate.html.erb +1 -0
  91. data/app/views/disco_app/charges/create.html.erb +1 -0
  92. data/app/views/disco_app/charges/new.html.erb +12 -0
  93. data/app/views/disco_app/frame/frame.html.erb +36 -0
  94. data/app/views/disco_app/install/installing.html.erb +7 -0
  95. data/app/views/disco_app/install/uninstalling.html.erb +1 -0
  96. data/app/views/disco_app/proxy_errors/404.html.erb +1 -0
  97. data/app/views/disco_app/shared/_card.html.erb +14 -0
  98. data/app/views/disco_app/shared/_section.html.erb +17 -0
  99. data/app/views/disco_app/subscriptions/new.html.erb +25 -0
  100. data/app/views/layouts/admin/_navbar.html.erb +25 -0
  101. data/app/views/layouts/admin.html.erb +27 -0
  102. data/app/views/layouts/application.html.erb +18 -0
  103. data/app/views/layouts/embedded_app.html.erb +41 -0
  104. data/app/views/layouts/embedded_app_modal.html.erb +17 -0
  105. data/app/views/sessions/new.html.erb +26 -0
  106. data/config/routes.rb +44 -0
  107. data/db/migrate/20150525000000_create_shops_if_not_existent.rb +15 -0
  108. data/db/migrate/20150525162112_add_status_to_shops.rb +5 -0
  109. data/db/migrate/20150525171422_add_meta_to_shops.rb +11 -0
  110. data/db/migrate/20150629210346_add_charge_status_to_shop.rb +5 -0
  111. data/db/migrate/20150814214025_add_more_meta_to_shops.rb +15 -0
  112. data/db/migrate/20151017231302_create_disco_app_plans.rb +13 -0
  113. data/db/migrate/20151017232027_create_disco_app_subscriptions.rb +15 -0
  114. data/db/migrate/20151017234409_move_shop_to_disco_app_engine.rb +5 -0
  115. data/db/migrate/20160112233706_create_disco_app_sessions.rb +12 -0
  116. data/db/migrate/20160113194418_add_shop_id_to_disco_app_sessions.rb +6 -0
  117. data/db/migrate/20160223111044_create_disco_app_settings.rb +8 -0
  118. data/db/migrate/20160301223215_update_plans.rb +22 -0
  119. data/db/migrate/20160301224558_update_subscriptions.rb +13 -0
  120. data/db/migrate/20160302104816_create_disco_app_recurring_application_charges.rb +14 -0
  121. data/db/migrate/20160302105259_create_disco_app_application_charges.rb +14 -0
  122. data/db/migrate/20160302134728_drop_charge_status_from_shops.rb +5 -0
  123. data/db/migrate/20160302142941_add_shopify_attributes_to_charges.rb +8 -0
  124. data/db/migrate/20160331093148_create_disco_app_plan_codes.rb +14 -0
  125. data/db/migrate/20160401044420_add_status_to_plan_codes.rb +5 -0
  126. data/db/migrate/20160401045551_add_amount_and_plan_code_to_disco_app_subscriptions.rb +7 -0
  127. data/lib/disco_app/configuration.rb +39 -0
  128. data/lib/disco_app/engine.rb +26 -0
  129. data/lib/disco_app/session.rb +14 -0
  130. data/lib/disco_app/support/file_fixtures.rb +23 -0
  131. data/lib/disco_app/test_help.rb +11 -0
  132. data/lib/disco_app/version.rb +3 -0
  133. data/lib/disco_app.rb +6 -0
  134. data/lib/generators/disco_app/USAGE +5 -0
  135. data/lib/generators/disco_app/adminify/adminify_generator.rb +35 -0
  136. data/lib/generators/disco_app/disco_app_generator.rb +164 -0
  137. data/lib/generators/disco_app/mailify/mailify_generator.rb +54 -0
  138. data/lib/generators/disco_app/monitorify/monitorify_generator.rb +28 -0
  139. data/lib/generators/disco_app/monitorify/templates/config/newrelic.yml +26 -0
  140. data/lib/generators/disco_app/monitorify/templates/initializers/rollbar.rb +12 -0
  141. data/lib/generators/disco_app/reactify/reactify_generator.rb +45 -0
  142. data/lib/generators/disco_app/templates/assets/javascripts/application.js +17 -0
  143. data/lib/generators/disco_app/templates/assets/stylesheets/application.scss +5 -0
  144. data/lib/generators/disco_app/templates/config/puma.rb +15 -0
  145. data/lib/generators/disco_app/templates/controllers/home_controller.rb +7 -0
  146. data/lib/generators/disco_app/templates/initializers/disco_app.rb +19 -0
  147. data/lib/generators/disco_app/templates/initializers/session_store.rb +2 -0
  148. data/lib/generators/disco_app/templates/initializers/shopify_app.rb +7 -0
  149. data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +7 -0
  150. data/lib/generators/disco_app/templates/root/Procfile +2 -0
  151. data/lib/generators/disco_app/templates/views/home/index.html.erb +2 -0
  152. data/lib/tasks/carrier_service.rake +10 -0
  153. data/lib/tasks/sessions.rake +9 -0
  154. data/lib/tasks/start.rake +3 -0
  155. data/lib/tasks/webhooks.rake +10 -0
  156. data/test/controllers/disco_app/admin/shops_controller_test.rb +54 -0
  157. data/test/controllers/disco_app/charges_controller_test.rb +91 -0
  158. data/test/controllers/disco_app/install_controller_test.rb +50 -0
  159. data/test/controllers/disco_app/subscriptions_controller_test.rb +73 -0
  160. data/test/controllers/disco_app/webhooks_controller_test.rb +58 -0
  161. data/test/controllers/home_controller_test.rb +92 -0
  162. data/test/controllers/proxy_controller_test.rb +42 -0
  163. data/test/disco_app_test.rb +7 -0
  164. data/test/dummy/Rakefile +6 -0
  165. data/test/dummy/app/assets/javascripts/application.js +17 -0
  166. data/test/dummy/app/assets/stylesheets/application.scss +5 -0
  167. data/test/dummy/app/controllers/application_controller.rb +6 -0
  168. data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +8 -0
  169. data/test/dummy/app/controllers/home_controller.rb +7 -0
  170. data/test/dummy/app/controllers/proxy_controller.rb +8 -0
  171. data/test/dummy/app/helpers/application_helper.rb +2 -0
  172. data/test/dummy/app/jobs/disco_app/app_installed_job.rb +16 -0
  173. data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +11 -0
  174. data/test/dummy/app/jobs/products_create_job.rb +7 -0
  175. data/test/dummy/app/jobs/products_delete_job.rb +7 -0
  176. data/test/dummy/app/jobs/products_update_job.rb +7 -0
  177. data/test/dummy/app/models/disco_app/shop.rb +15 -0
  178. data/test/dummy/app/models/product.rb +6 -0
  179. data/test/dummy/app/views/home/index.html.erb +2 -0
  180. data/test/dummy/bin/bundle +3 -0
  181. data/test/dummy/bin/rails +4 -0
  182. data/test/dummy/bin/rake +4 -0
  183. data/test/dummy/bin/setup +29 -0
  184. data/test/dummy/config/application.rb +38 -0
  185. data/test/dummy/config/boot.rb +5 -0
  186. data/test/dummy/config/database.codeship.yml +23 -0
  187. data/test/dummy/config/database.yml +20 -0
  188. data/test/dummy/config/environment.rb +5 -0
  189. data/test/dummy/config/environments/development.rb +41 -0
  190. data/test/dummy/config/environments/production.rb +85 -0
  191. data/test/dummy/config/environments/test.rb +42 -0
  192. data/test/dummy/config/initializers/assets.rb +11 -0
  193. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  194. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  195. data/test/dummy/config/initializers/disco_app.rb +19 -0
  196. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  197. data/test/dummy/config/initializers/inflections.rb +16 -0
  198. data/test/dummy/config/initializers/mime_types.rb +4 -0
  199. data/test/dummy/config/initializers/omniauth.rb +9 -0
  200. data/test/dummy/config/initializers/session_store.rb +2 -0
  201. data/test/dummy/config/initializers/shopify_app.rb +7 -0
  202. data/test/dummy/config/initializers/shopify_session_repository.rb +7 -0
  203. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  204. data/test/dummy/config/locales/en.yml +23 -0
  205. data/test/dummy/config/routes.rb +10 -0
  206. data/test/dummy/config/secrets.yml +22 -0
  207. data/test/dummy/config.ru +4 -0
  208. data/test/dummy/db/migrate/20160307182229_create_products.rb +11 -0
  209. data/test/dummy/db/schema.rb +138 -0
  210. data/test/dummy/public/404.html +67 -0
  211. data/test/dummy/public/422.html +67 -0
  212. data/test/dummy/public/500.html +66 -0
  213. data/test/dummy/public/favicon.ico +0 -0
  214. data/test/fixtures/api/widget_store/charges/activate_application_charge_request.json +16 -0
  215. data/test/fixtures/api/widget_store/charges/activate_application_charge_response.json +1 -0
  216. data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_request.json +20 -0
  217. data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_response.json +1 -0
  218. data/test/fixtures/api/widget_store/charges/create_application_charge_request.json +9 -0
  219. data/test/fixtures/api/widget_store/charges/create_application_charge_response.json +16 -0
  220. data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_request.json +9 -0
  221. data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_response.json +20 -0
  222. data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_request.json +9 -0
  223. data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_response.json +20 -0
  224. data/test/fixtures/api/widget_store/charges/get_accepted_application_charge_response.json +16 -0
  225. data/test/fixtures/api/widget_store/charges/get_accepted_recurring_application_charge_response.json +20 -0
  226. data/test/fixtures/api/widget_store/charges/get_declined_application_charge_response.json +16 -0
  227. data/test/fixtures/api/widget_store/charges/get_declined_recurring_application_charge_response.json +20 -0
  228. data/test/fixtures/api/widget_store/charges/get_pending_application_charge_response.json +16 -0
  229. data/test/fixtures/api/widget_store/charges/get_pending_recurring_application_charge_response.json +20 -0
  230. data/test/fixtures/api/widget_store/shop.json +46 -0
  231. data/test/fixtures/api/widget_store/webhooks.json +1 -0
  232. data/test/fixtures/disco_app/application_charges.yml +11 -0
  233. data/test/fixtures/disco_app/plan_codes.yml +6 -0
  234. data/test/fixtures/disco_app/plans.yml +37 -0
  235. data/test/fixtures/disco_app/recurring_application_charges.yml +11 -0
  236. data/test/fixtures/disco_app/shops.yml +10 -0
  237. data/test/fixtures/disco_app/subscriptions.yml +21 -0
  238. data/test/fixtures/products.yml +4 -0
  239. data/test/fixtures/webhooks/app_uninstalled.json +46 -0
  240. data/test/fixtures/webhooks/product_created.json +167 -0
  241. data/test/fixtures/webhooks/product_deleted.json +3 -0
  242. data/test/fixtures/webhooks/product_updated.json +167 -0
  243. data/test/integration/synchronises_test.rb +55 -0
  244. data/test/jobs/disco_app/app_installed_job_test.rb +42 -0
  245. data/test/jobs/disco_app/app_uninstalled_job_test.rb +30 -0
  246. data/test/models/disco_app/plan_test.rb +5 -0
  247. data/test/models/disco_app/session_test.rb +31 -0
  248. data/test/models/disco_app/shop_test.rb +27 -0
  249. data/test/services/disco_app/charges_service_test.rb +104 -0
  250. data/test/services/disco_app/subscription_service_test.rb +59 -0
  251. data/test/support/test_file_fixtures.rb +29 -0
  252. data/test/support/test_shopify_api.rb +16 -0
  253. data/test/test_helper.rb +52 -0
  254. metadata +660 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6d121a39b30f43fccab67728b99a8bc4e4aed5ef0fea0aaaba6c72f35b2c30b3
4
+ data.tar.gz: 8a6dd1711f023374e251243c661c4eec548aa1613ab39175c4e5b07975400579
5
+ SHA512:
6
+ metadata.gz: 8d9ad557bccac5b7d620b2e6ffab730588394c8ab8570836c376dbb72080da66e79ddec488efcb9f638c44a5a57d793b13022fd96fe50c29d0fe5700d4fa9e04
7
+ data.tar.gz: bfe171a5488905b6704eb84e39f5f1a4c1a6603d337b18df96d8e8923c4706b889595cf6532ea83c1f28fe77f6f91c0bd476b9e00018f7fb95b5aba43ab4007b
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>
@@ -0,0 +1,65 @@
1
+ var FilterableShopList = React.createClass({
2
+
3
+ getDefaultProps: function() {
4
+ return {
5
+ filterTabs: [
6
+ { label: 'All Shops', filter: {} },
7
+ { label: 'Never Installed', filter: { 'filter[status]': 'never_installed' } },
8
+ { label: 'Awaiting Install', filter: { 'filter[status]': 'awaiting_install' } },
9
+ { label: 'Installing', filter: { 'filter[status]': 'installing' } },
10
+ { label: 'Installed', filter: { 'filter[status]': 'installed' } },
11
+ { label: 'Awaiting Uninstall', filter: { 'filter[status]': 'awaiting_uninstall' } },
12
+ { label: 'Uninstalling', filter: { 'filter[status]': 'uninstalling' } },
13
+ { label: 'Uninstalled', filter: { 'filter[status]': 'uninstalled' } }
14
+ ],
15
+ availableFilters: {
16
+ 'filter[status]': {
17
+ getLabel: function(value) {
18
+ return 'Status is ' + value;
19
+ }
20
+ }
21
+ }
22
+ }
23
+ },
24
+
25
+ getInitialState: function() {
26
+ return {
27
+ filter: {}
28
+ };
29
+ },
30
+
31
+ onFilterReplace: function(filter) {
32
+ this.setState({
33
+ filter: filter
34
+ });
35
+ },
36
+
37
+ onFilterSet: function(name, value) {
38
+ this.onFiltersSet([{
39
+ name: name,
40
+ value: value
41
+ }]);
42
+ },
43
+
44
+ onFiltersSet: function(filters) {
45
+ var nextFilter = $.extend({}, this.state.filter);
46
+ filters.forEach(function(filter) {
47
+ if(!filter.value) {
48
+ delete nextFilter[filter.name];
49
+ } else {
50
+ nextFilter[filter.name] = filter.value;
51
+ }
52
+ });
53
+ this.onFilterReplace(nextFilter);
54
+ },
55
+
56
+ render: function() {
57
+ return (
58
+ <div className="next-card">
59
+ <ShopFilterTabs filterTabs={this.props.filterTabs} filter={this.state.filter} onFilterReplace={this.onFilterReplace} />
60
+ <ShopList shopsUrl={this.props.shopsUrl} editShopUrl={this.props.editShopUrl} filter={this.state.filter} />
61
+ </div>
62
+ );
63
+ }
64
+
65
+ });
@@ -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
+ });
@@ -0,0 +1,21 @@
1
+ var ShopFilterTabs = React.createClass({
2
+
3
+ onFilterTabSelected: function(filterTab) {
4
+ this.props.onFilterReplace(filterTab.filter);
5
+ },
6
+
7
+ render: function() {
8
+ var filterTabNodes = this.props.filterTabs.map(function(filterTab) {
9
+ return (
10
+ <ShopFilterTab key={filterTab.label} filter={this.props.filter} filterTab={filterTab} onFilterTabSelected={this.onFilterTabSelected} />
11
+ )
12
+ }, this);
13
+
14
+ return (
15
+ <ul className="next-tab__list">
16
+ {filterTabNodes}
17
+ </ul>
18
+ )
19
+ }
20
+
21
+ });
@@ -0,0 +1,140 @@
1
+ var ShopList = React.createClass({
2
+
3
+ getDefaultProps: function() {
4
+ return {
5
+ pageSize: 50
6
+ }
7
+ },
8
+
9
+ getInitialState: function() {
10
+ return {
11
+ shops: [],
12
+ page: 1
13
+ }
14
+ },
15
+
16
+ componentDidMount: function() {
17
+ this.getShops();
18
+ $(document).on('shops.changed', this.onShopsChanged);
19
+ },
20
+
21
+ componentWillUnmount: function() {
22
+ $(document).off('shops.changed', this.onShopsChanged);
23
+ },
24
+
25
+ componentDidUpdate: function (prevProps, prevState) {
26
+ if(prevProps.filter != this.props.filter) {
27
+ this.getShops();
28
+ }
29
+ if(prevState.page != this.state.page) {
30
+ this.getShops();
31
+ }
32
+ },
33
+
34
+ onPageChanged: function(increment) {
35
+ this.setState({page: this.state.page + increment});
36
+ },
37
+
38
+ onShopsChanged: function() {
39
+ this.setState({page: 1});
40
+ this.getShops();
41
+ },
42
+
43
+ getShops: function() {
44
+ //ShopifyApp.Bar.loadingOn();
45
+
46
+ // Set up request data with filter and pagination parameters.
47
+ var data = $.extend({
48
+ 'page[size]': this.props.pageSize,
49
+ 'page[number]': this.state.page
50
+ }, this.props.filter);
51
+
52
+ // Make the request to fetch the order list.
53
+ $.getJSON(this.props.shopsUrl, data, function(result) {
54
+ if(this.isMounted()) {
55
+ this.setState({
56
+ shops: result.data
57
+ });
58
+ }
59
+ }.bind(this))
60
+ .always(function() {
61
+ //ShopifyApp.Bar.loadingOff();
62
+ });
63
+ },
64
+
65
+ render: function() {
66
+ var shopRows = this.state.shops.map(function(shop) {
67
+ return (
68
+ <ShopRow shop={shop} editShopUrl={this.props.editShopUrl} key={shop.id} />
69
+ )
70
+ }.bind(this));
71
+
72
+ return (
73
+ <div>
74
+ <div className="next-card__section">
75
+ <table className="table-hover expanded">
76
+ <thead>
77
+ <tr>
78
+ <th>ID</th>
79
+ <th>Shopify Domain</th>
80
+ <th>Status</th>
81
+ <th>Email</th>
82
+ <th>Country Name</th>
83
+ <th>Currency</th>
84
+ <th>Domain</th>
85
+ <th>Plan</th>
86
+ <th>Created</th>
87
+ <th>Installed Duration</th>
88
+ </tr>
89
+ </thead>
90
+ <tbody>
91
+ {shopRows}
92
+ </tbody>
93
+ </table>
94
+ </div>
95
+ <div className="next-card__section">
96
+ <div className="next-grid next-grid--no-padding next-grid--center-aligned">
97
+ <div className="next-grid__cell next-grid__cell--no-flex">
98
+ <ShopList.Paginator page={this.state.page} pageSize={this.props.pageSize} items={this.state.shops} onPageChanged={this.onPageChanged} />
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ )
104
+ }
105
+
106
+ });
107
+
108
+ /**
109
+ * Paginator.
110
+ */
111
+ ShopList.Paginator = React.createClass({
112
+
113
+ handlePreviousClick: function(e) {
114
+ this.props.onPageChanged(-1);
115
+ },
116
+
117
+ handleNextClick: function(e) {
118
+ this.props.onPageChanged(1);
119
+ },
120
+
121
+ render: function() {
122
+ return (
123
+ <div className="btn-group" role="group">
124
+ <ShopList.PaginatorButton label="&lsaquo;" isDisabled={this.props.page < 2} onClick={this.handlePreviousClick} />
125
+ <ShopList.PaginatorButton label="&rsaquo;" isDisabled={this.props.items.length < this.props.pageSize} onClick={this.handleNextClick} />
126
+ </div>
127
+ )
128
+ }
129
+
130
+ });
131
+
132
+ /**
133
+ * Individual button within a paginator.
134
+ */
135
+ ShopList.PaginatorButton = (props) => {
136
+ var className = 'btn btn-default' + (props.isDisabled ? ' disabled' : '');
137
+ return (
138
+ <button className={className} disabled={props.isDisabled} onClick={props.onClick}>{props.label}</button>
139
+ )
140
+ };
@@ -0,0 +1,27 @@
1
+ var ShopRow = (props) => {
2
+
3
+ var shop = props.shop,
4
+ editShopUrl = props.editShopUrl.replace(':id', shop.id),
5
+ shopifyDomain = shop.attributes['shopify_domain'],
6
+ countryName = shop.attributes['country_name'],
7
+ currency = shop.attributes['currency'],
8
+ domainName = shop.attributes['domain'],
9
+ planName = shop.attributes['plan_display_name'],
10
+ createdDate = shop.attributes['created_at'],
11
+ installedDuration = shop.attributes['installed_duration']
12
+
13
+ return (
14
+ <tr>
15
+ <td><a href={editShopUrl}>#{shop.id}</a></td>
16
+ <td>{shopifyDomain}</td>
17
+ <td>{shop.attributes.status}</td>
18
+ <td>{shop.attributes.email}</td>
19
+ <td>{countryName}</td>
20
+ <td>{shop.attributes.currency}</td>
21
+ <td>{shop.attributes.domain}</td>
22
+ <td>{planName}</td>
23
+ <td>{createdDate}</td>
24
+ <td>{installedDuration}</td>
25
+ </tr>
26
+ )
27
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * ShopifyAdminLink
3
+ *
4
+ * Renders a link pointing to an object (such as an order or customer) inside
5
+ * the given shop's Shopify admin. This helper makes it easy to create links
6
+ * to objects within the admin that support both right-clicking and opening in
7
+ * a new tab as well as capturing a left click and redirecting to the relevant
8
+ * object using `ShopifyApp.redirect()`.
9
+ *
10
+ * This component is the React equivalent to the link_to_shopify_admin helper
11
+ * found in app/helpers/disco_app/application_helper.rb.
12
+ */
13
+ var ShopifyAdminLink = React.createClass({
14
+
15
+ handleClick: function(e) {
16
+ e.preventDefault();
17
+ ShopifyApp.redirect(this.props.href);
18
+ },
19
+
20
+ render: function() {
21
+ var href = ShopifyApp.shopOrigin + '/admin' + this.props.href;
22
+ return (
23
+ <a className={this.props.className} href={href} onClick={this.handleClick}>
24
+ {this.props.label}
25
+ </a>
26
+ )
27
+ }
28
+
29
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * disco_app/components.js
3
+ * React components common to Disco applications.
4
+ */
5
+ //= require_tree ./components
@@ -0,0 +1,7 @@
1
+ /**
2
+ * disco_app/disco_app.js
3
+ * Base Javascript for Disco applications.
4
+ * Assumes that jQuery will be loaded in the parent application.js.
5
+ */
6
+ //= require bootstrap-sprockets
7
+ //= require disco_app/shopify-turbolinks
@@ -0,0 +1,152 @@
1
+ /**
2
+ * frame.js
3
+ *
4
+ * The FrameApp object is a lightweight Javascript object intended to mock the `postMessage` endpoint for Embedded Apps
5
+ * in the Shopify Admin panel. Eventually, we hope to mock all of the functionality provided by the Shopify Embedded App
6
+ * SDK.
7
+ */
8
+ (function() {
9
+
10
+ window.FrameApp = (function() {
11
+
12
+ FrameApp.name = 'Shopify Dev Frame';
13
+
14
+ function FrameApp() {}
15
+
16
+
17
+ /* Initialisation, configuration and helpers.
18
+ ================================================== */
19
+
20
+ /**
21
+ * Initialise the FrameApp - load configuration, set up event handlers.
22
+ *
23
+ * @param config
24
+ * @returns {*}
25
+ */
26
+ FrameApp.init = function(config) {
27
+ var _this = this;
28
+ if (config == null) {
29
+ config = {};
30
+ }
31
+ this.loadConfig(config);
32
+
33
+ // Use addEventListener if available, otherwise fall back to attachEvent.
34
+ if (window.addEventListener) {
35
+ this.iframe.addEventListener("load", FrameApp.__iframeLoadCallback, false);
36
+ return window.addEventListener("message", FrameApp.__addEventMessageCallback, false);
37
+ }
38
+
39
+ this.iframe.attachEvent("load", FrameApp.__iframeLoadCallback);
40
+ return window.attachEvent("onMessage", FrameApp.__addEventMessageCallback);
41
+ };
42
+
43
+ /**
44
+ * Load configuration for the FrameApp. Set defaults if not provided.
45
+ * @param config
46
+ */
47
+ FrameApp.loadConfig = function(config) {
48
+ this.shopOrigin = config.shopOrigin;
49
+ this.debug = !!config.debug;
50
+ this.iframe = config.iframe;
51
+ if (!this.iframe) {
52
+ this.log("FrameApp error: no <iframe> specified.");
53
+ }
54
+ FrameApp.log('FrameApp configuration loaded.');
55
+ };
56
+
57
+ /**
58
+ * Log a message to the console, if the app was configured in debug mode.
59
+ *
60
+ * @param message
61
+ * @param force
62
+ * @returns {*}
63
+ */
64
+ FrameApp.log = function(message, force) {
65
+ if ((typeof console !== "undefined" && console !== null ? console.log : void 0) && (this.debug || force)) {
66
+ return console.log(message);
67
+ }
68
+ };
69
+
70
+
71
+ /* Message sending and event handling.
72
+ ================================================== */
73
+
74
+ FrameApp.__messageHandlers = {};
75
+
76
+ /**
77
+ * Post a message to the <iframe>.
78
+ *
79
+ * @param message
80
+ * @param data
81
+ * @returns {*}
82
+ */
83
+ FrameApp.postMessage = function(message, data) {
84
+ var json;
85
+ json = JSON.stringify({
86
+ message: message,
87
+ data: data
88
+ });
89
+ FrameApp.log("FrameApp client sent " + json + " to ShopifyApp.");
90
+ return this.iframe.contentWindow.postMessage(json, '*');
91
+ };
92
+
93
+ /**
94
+ * Add a handler for a received message.
95
+ *
96
+ * @param message
97
+ * @param fn
98
+ * @returns {Number|*}
99
+ * @private
100
+ */
101
+ FrameApp.__addMessageHandler = function(message, fn) {
102
+ if (typeof message === "function") {
103
+ fn = message;
104
+ message = void 0;
105
+ }
106
+ if (!FrameApp.__messageHandlers[message]) {
107
+ FrameApp.__messageHandlers[message] = [];
108
+ }
109
+ return FrameApp.__messageHandlers[message].push(fn);
110
+ };
111
+
112
+ /**
113
+ * Callback triggered when a postMessage message is received.
114
+ *
115
+ * @param e
116
+ * @returns {*}
117
+ * @private
118
+ */
119
+ FrameApp.__addEventMessageCallback = function(e) {
120
+ var handler, handlers, message, submitForm, _i, _len;
121
+ FrameApp.log("FrameApp client received " + e.data + " from " + e.origin);
122
+ message = JSON.parse(e.data);
123
+ handlers = [];
124
+ if (FrameApp.__messageHandlers[message.message]) {
125
+ handlers = handlers.concat(FrameApp.__messageHandlers[message.message]);
126
+ }
127
+ if (FrameApp.__messageHandlers[void 0]) {
128
+ handlers = handlers.concat(FrameApp.__messageHandlers[void 0]);
129
+ }
130
+ for (_i = 0, _len = handlers.length; _i < _len; _i++) {
131
+ handler = handlers[_i];
132
+ handler(message.message, message.data);
133
+ }
134
+ };
135
+
136
+ /**
137
+ * Callback triggered when our iFrame is loaded.
138
+ *
139
+ * @param e
140
+ * @private
141
+ */
142
+ FrameApp.__iframeLoadCallback = function(e) {
143
+ FrameApp.postMessage('Shopify.API.initialize', {
144
+ 'hi': 'there!'
145
+ });
146
+ };
147
+
148
+ return FrameApp;
149
+
150
+ }).call(this);
151
+
152
+ }).call(this);
@@ -0,0 +1,7 @@
1
+ /**
2
+ * disco_app/shopify-turbolinks.js
3
+ * Some tweaks to help Turbolinks play nicely with the Embedded App SDK.
4
+ */
5
+ jQuery(document).on('page:load', function(e) {
6
+ ShopifyApp.pushState(window.location.pathname);
7
+ });
@@ -0,0 +1,54 @@
1
+ //
2
+ // Select the Bootstrap components to pull in.
3
+ // --------------------------------------------------
4
+
5
+ // Core variables and mixins
6
+ @import "bootstrap/variables";
7
+ @import "bootstrap/mixins";
8
+
9
+ // Reset and dependencies
10
+ @import "bootstrap/normalize";
11
+ //@import "bootstrap/print";
12
+ //@import "bootstrap/glyphicons";
13
+
14
+ // Core CSS
15
+ @import "bootstrap/scaffolding";
16
+ @import "bootstrap/type";
17
+ //@import "bootstrap/code";
18
+ @import "bootstrap/grid";
19
+ //@import "bootstrap/tables";
20
+ @import "bootstrap/forms";
21
+ @import "bootstrap/buttons";
22
+
23
+ // Components
24
+ @import "bootstrap/component-animations";
25
+ @import "bootstrap/dropdowns";
26
+ @import "bootstrap/button-groups";
27
+ @import "bootstrap/input-groups";
28
+ @import "bootstrap/navs";
29
+ @import "bootstrap/navbar";
30
+ //@import "bootstrap/breadcrumbs";
31
+ //@import "bootstrap/pagination";
32
+ //@import "bootstrap/pager";
33
+ @import "bootstrap/labels";
34
+ @import "bootstrap/badges";
35
+ //@import "bootstrap/jumbotron";
36
+ @import "bootstrap/thumbnails";
37
+ @import "bootstrap/alerts";
38
+ @import "bootstrap/progress-bars";
39
+ @import "bootstrap/media";
40
+ @import "bootstrap/list-group";
41
+ @import "bootstrap/panels";
42
+ //@import "bootstrap/responsive-embed";
43
+ //@import "bootstrap/wells";
44
+ @import "bootstrap/close";
45
+
46
+ // Components w/ JavaScript
47
+ //@import "bootstrap/modals";
48
+ //@import "bootstrap/tooltip";
49
+ //@import "bootstrap/popovers";
50
+ //@import "bootstrap/carousel";
51
+
52
+ // Utility classes
53
+ @import "bootstrap/utilities";
54
+ @import "bootstrap/responsive-utilities";