Compare commits
No commits in common. "develop" and "change_to_affiliate_program" have entirely different histories.
develop
...
change_to_
|
|
@ -1,25 +0,0 @@
|
|||
name: Build Admin
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: dagger
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://github.com/actions/checkout@v4
|
||||
|
||||
- name: Install Dagger
|
||||
run: |
|
||||
curl -L https://dl.dagger.io/dagger/install.sh | sh
|
||||
sudo mv bin/dagger /usr/local/bin/
|
||||
|
||||
- name: Login to Gitea Registry
|
||||
run: echo "${{ gitea.token }}" | docker login git.staging.jamkazam.com -u ${{ gitea.actor }} --password-stdin
|
||||
|
||||
- name: Build and Publish with Dagger
|
||||
working-directory: ./admin
|
||||
run: |
|
||||
dagger call build-local --source=. --repo-root=../ publish --address=git.staging.jamkazam.com/seth/jam-cloud-admin:latest
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
name: Environment Orchestrator
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
orchestrate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Component Deployment Gatekeeper
|
||||
run: |
|
||||
# JAM_CLUSTER_ENV should be set to 'staging' or 'production' in the Gitea Runner
|
||||
ENV="${JAM_CLUSTER_ENV:-staging}"
|
||||
echo "🌐 Cluster Environment: $ENV"
|
||||
|
||||
# 1. Extract modes for this environment
|
||||
ADMIN_MODE=$(jq -r ".environments.$ENV.admin" .jk-deploy.json)
|
||||
WEB_MODE=$(jq -r ".environments.$ENV.web" .jk-deploy.json)
|
||||
WS_MODE=$(jq -r ".environments.$ENV.[\"websocket-gateway\"]" .jk-deploy.json)
|
||||
|
||||
# 2. Conditional Execution
|
||||
if [ "$ADMIN_MODE" == "short-circuit" ]; then
|
||||
echo "⚡ ADMIN: Short-circuit detected. Deploying immediately..."
|
||||
cd admin && dagger call ship --source=.
|
||||
else
|
||||
echo "⏸️ ADMIN: Mode is $ADMIN_MODE. Skipping short-circuit deploy."
|
||||
fi
|
||||
|
||||
if [ "$WEB_MODE" == "short-circuit" ]; then
|
||||
echo "⚡ WEB: Short-circuit detected. Deploying immediately..."
|
||||
cd web && dagger call ship --source=.
|
||||
else
|
||||
echo "⏸️ WEB: Mode is $WEB_MODE. Skipping short-circuit deploy."
|
||||
fi
|
||||
|
||||
if [ "$WS_MODE" == "short-circuit" ]; then
|
||||
echo "⚡ WS-GATEWAY: Short-circuit detected. Deploying immediately..."
|
||||
cd websocket-gateway && just ship
|
||||
else
|
||||
echo "⏸️ WS-GATEWAY: Mode is $WS_MODE. Skipping short-circuit deploy."
|
||||
fi
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
name: Test Runner
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "Runner is working!"
|
||||
|
|
@ -8,7 +8,3 @@ HTML
|
|||
coverage
|
||||
dump.rdb
|
||||
working.png
|
||||
ruby/.rails5-gems
|
||||
web/.rails5-gems
|
||||
websocket-gateway/.rails5-gems
|
||||
.pg_data/
|
||||
|
|
@ -1 +0,0 @@
|
|||
2.4.1
|
||||
|
|
@ -21,6 +21,3 @@ artifacts
|
|||
.idea
|
||||
BUILD_NUMBER
|
||||
# Gemfile.lock
|
||||
Gemfile.alt.lock
|
||||
.byebug_history
|
||||
.ruby-version
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
2.4.1
|
||||
|
|
@ -94,12 +94,7 @@ gem 'eventmachine', '1.2.3'
|
|||
gem 'amqp', '0.9.8'
|
||||
#gem 'logging-rails', :require => 'logging/rails'
|
||||
#gem 'pg_migrate', '0.1.14'
|
||||
if ENV["MODERN_OS"] == "1"
|
||||
gem 'pg', '0.21.0'
|
||||
else
|
||||
# on mac, bundle config build.pg --with-cflags="-Wno-error=implicit-function-declaration"
|
||||
gem 'pg', '0.17.1', :platform => [:mri, :mswin, :mingw]
|
||||
end
|
||||
gem 'pg', '0.17.1', :platform => [:mri, :mswin, :mingw]
|
||||
gem 'ruby-protocol-buffers', '1.2.2'
|
||||
gem 'sendgrid', '1.2.0'
|
||||
gem 'geokit-rails'
|
||||
|
|
|
|||
|
|
@ -1,172 +0,0 @@
|
|||
source 'http://rubygems.org'
|
||||
|
||||
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
|
||||
ruby_version = ENV["JAM_RUBY_VERSION"]
|
||||
ruby_version = "2.3.1" if ruby_version.nil?
|
||||
|
||||
ruby ruby_version
|
||||
|
||||
devenv = ENV["BUILD_NUMBER"].nil?
|
||||
|
||||
if devenv
|
||||
#gem 'jam_db', :path=> "../db/target/ruby_package"
|
||||
gem 'jampb', :path => "../pb/target/ruby/jampb"
|
||||
gem 'jam_ruby', :path => "../ruby"
|
||||
else
|
||||
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' do
|
||||
#gem 'jam_db', "0.1.#{ENV["BUILD_NUMBER"]}"
|
||||
gem 'jampb', "0.1.#{ENV["BUILD_NUMBER"]}"
|
||||
gem 'jam_ruby', "0.1.#{ENV["BUILD_NUMBER"]}"
|
||||
ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true"
|
||||
end
|
||||
end
|
||||
|
||||
gem 'activeadmin_addons'
|
||||
gem 'json', '1.8.6'
|
||||
gem 'rails', '= 4.2.8'
|
||||
gem 'protected_attributes'
|
||||
gem 'rails-observers'
|
||||
|
||||
|
||||
# PINNED TO SUPPORT BOTH 2.3.1 and 2.4.1 Ruby simultaneously
|
||||
# This should be the same in ruby/admin/web/websocket-gateway
|
||||
#######
|
||||
gem 'nokogiri', '1.10.10' # added to pin before 1.11.0, which requires at leaost ruby 2.5. unpin we go above
|
||||
gem 'sprockets', '3.6.3' # added to pin before 4.0.0, which requiurse at least ruby 2.5
|
||||
gem 'fog-brightbox', '0.11.0' # pinned until we are on ruby 2.5; then remove
|
||||
gem 'faraday', '0.9.2' # pinned untnil we are on ruby 2.5; then remove
|
||||
gem 'ruby-prof', '0.15.9' # pinned until we are on ruby 2.5; then remove
|
||||
gem 'rubyzip', '1.2.1' # pinned until we are on ruby 2.5; then remove
|
||||
gem 'recurly', '2.18.16' # should upgrade to 3.x when we have time to validaate
|
||||
gem 'icalendar', '2.4.0' # pinned until we are on ruby 2.5; then remove
|
||||
gem 'email_validator', '1.6.0' # pinned until we are on ruby 2.5, then remove
|
||||
gem 'redis', '3.3.3' # pinned until we are on 2.5; then remove
|
||||
gem 'redis-namespace', '1.5.3' # pinned until we are on 2.5; then remove
|
||||
gem 'oj', '3.1.3' # pinned until we are on 2.5; then remove
|
||||
gem 'bcrypt', '3.1.15'
|
||||
gem 'sass-rails', '5.0.7' # compiler mismatch issue between build and www
|
||||
gem 'sass', '3.5.5 '# compiler mismatch issue between build and www
|
||||
#######
|
||||
|
||||
gem 'bootstrap-sass', '2.0.4'
|
||||
|
||||
gem 'coffee-rails' #, '~> 3.2.1'
|
||||
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
# gem 'therubyracer', :platforms => :ruby
|
||||
|
||||
gem 'kickbox'
|
||||
gem 'uglifier' #, '>= 1.0.3'
|
||||
gem 'net-ssh'
|
||||
gem 'sprockets-rails', '2.3.2'
|
||||
|
||||
# this version is pinned due to this: https://github.com/gregbell/active_admin/issues/1939
|
||||
gem 'coffee-script-source' #, '~> 1.4.0' # ADD THIS LINE, 1.5.0 doesn't compile ActiveAdmin JavaScript files
|
||||
gem 'devise' #, '3.3.0'
|
||||
gem 'will_paginate' #, '3.0.3'
|
||||
gem 'bootstrap-will_paginate', '0.0.6'
|
||||
gem 'carrierwave', '0.11.2' #, '0.9.0'
|
||||
gem 'carrierwave_direct'
|
||||
gem 'uuidtools', '2.1.2'
|
||||
gem 'jquery-ui-rails'# , '5.0.5' #, '4.2.1'
|
||||
gem 'jquery-rails'# , '4.1.1' # both this and jquery-ui-rails are pinned; if you unpin, jquery/autocomplete is missing during precomplie
|
||||
gem 'rails-jquery-autocomplete' # This is the maintained version of rails3-jquery-autocomplete
|
||||
gem 'activeadmin' #, '1.0.0.pre4'# github: 'activeadmin', branch: 'master'
|
||||
gem 'activeadmin-searchable_select'
|
||||
gem 'mime-types', '1.25'
|
||||
#gem 'meta_search'
|
||||
gem 'fog'
|
||||
gem 'xmlrpc'
|
||||
gem 'unf', '0.1.3' #optional fog dependency
|
||||
gem 'country-select'
|
||||
gem 'aasm' #, '3.0.16'
|
||||
gem 'postgres-copy', '0.6.0'
|
||||
gem 'aws-sdk', '~> 1'
|
||||
gem 'bugsnag', '5.3.2'
|
||||
gem 'gon'
|
||||
gem 'cocoon'
|
||||
gem 'haml-rails'
|
||||
gem 'resque'
|
||||
gem 'resque-retry'
|
||||
gem 'resque-failed-job-mailer'
|
||||
gem 'resque-lonely_job', '~> 1.0.0'
|
||||
gem 'eventmachine', '1.2.3'
|
||||
gem 'amqp', '0.9.8'
|
||||
#gem 'logging-rails', :require => 'logging/rails'
|
||||
#gem 'pg_migrate', '0.1.14'
|
||||
if ENV["MODERN_OS"] == "1"
|
||||
gem 'pg', '0.21.0'
|
||||
else
|
||||
# on mac, bundle config build.pg --with-cflags="-Wno-error=implicit-function-declaration"
|
||||
gem 'pg', '0.17.1', :platform => [:mri, :mswin, :mingw]
|
||||
end
|
||||
gem 'ruby-protocol-buffers', '1.2.2'
|
||||
gem 'sendgrid', '1.2.0'
|
||||
gem 'geokit-rails'
|
||||
gem 'postgres_ext' #, '1.0.0'
|
||||
gem 'resque_mailer'
|
||||
gem 'rest-client'
|
||||
gem 'iso-639'
|
||||
gem 'sanitize'
|
||||
gem 'slim'
|
||||
#gem 'influxdb', '0.1.8'
|
||||
#gem 'influxdb-rails', '0.1.10'
|
||||
gem 'influxdb', '0.3.14'
|
||||
gem 'influxdb-rails', '0.1.12'
|
||||
gem 'sendgrid_toolkit', '>= 1.1.1'
|
||||
gem 'stripe'
|
||||
gem 'zip-codes'
|
||||
gem 'best_in_place' #, github: 'bernat/best_in_place'
|
||||
gem 'auto_strip_attributes', '2.6.0'
|
||||
gem 'elasticsearch'
|
||||
|
||||
gem 'logging', '1.7.2'
|
||||
|
||||
#group :libv8 do
|
||||
# gem 'libv8', "~> 4.5.95"
|
||||
#end
|
||||
|
||||
|
||||
# To use Jbuilder templates for JSON
|
||||
# gem 'jbuilder'
|
||||
|
||||
group :production do
|
||||
gem 'unicorn'
|
||||
end
|
||||
|
||||
group :package do
|
||||
gem 'fpm'
|
||||
end
|
||||
|
||||
# Deploy with Capistrano
|
||||
# gem 'capistrano'
|
||||
|
||||
# To use debugger
|
||||
#gem 'debugger' # not working with 2.1.2p95
|
||||
|
||||
group :development, :test do
|
||||
gem 'capybara', '2.13.0'
|
||||
gem 'rspec-rails' #, '2.14.2'
|
||||
gem 'jasmine', '1.3.1'
|
||||
gem 'execjs', '1.4.0'
|
||||
#gem 'therubyracer' #, '0.11.0beta8'
|
||||
gem 'factory_girl_rails' # , '4.1.0'
|
||||
gem 'database_cleaner' #, '0.7.0'
|
||||
gem 'launchy', '2.4.3' # can unpin when go to ruby 2.4+
|
||||
gem 'faker', '1.3.0'
|
||||
gem 'puma'
|
||||
gem 'test-unit'
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'simplecov', '~> 0.7.1'
|
||||
gem 'simplecov-rcov'
|
||||
# gem 'capybara-webkit'
|
||||
# gem 'capybara-screenshot', '0.3.22' # 1.0.0 broke compat with rspec. maybe we need newer rspec
|
||||
# gem 'poltergeist'
|
||||
end
|
||||
|
||||
gem 'pry'
|
||||
gem 'pry-remote'
|
||||
gem 'pry-stack_explorer'
|
||||
#gem 'pry-debugger'
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
module AdCampaignsHelper
|
||||
def self.spacer(val, total)
|
||||
percentage = ((val * 100) / total.to_f).round(1).to_s
|
||||
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
|
||||
end
|
||||
|
||||
def self.cac(campaign)
|
||||
if campaign.subscribed && campaign.subscribed > 0
|
||||
(campaign.spend/campaign.subscribed.to_f).round(2)
|
||||
end
|
||||
end
|
||||
|
||||
def self.cac_divide_by_ltv(campaign)
|
||||
customer_ltv = GenericState.singleton.customer_ltv
|
||||
if cac(campaign) && customer_ltv && customer_ltv > 0
|
||||
return (cac(campaign)/customer_ltv.to_f).round(2)
|
||||
end
|
||||
end
|
||||
|
||||
def self.format_number(num)
|
||||
if num
|
||||
num.to_s.reverse.scan(/\d{3}|.+/).join(",").reverse
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
ActiveAdmin.register JamRuby::AdCampaign, as: 'AdCampaign' do
|
||||
menu :label => 'Ad Campaigns', :parent => 'Reports'
|
||||
before_filter :skip_sidebar!, :only => :index
|
||||
config.batch_actions = false
|
||||
config.clear_action_items!
|
||||
config.sort_order = "users.origin_utm_campaign DESC"
|
||||
config.per_page = 100
|
||||
config.paginate = true
|
||||
|
||||
|
||||
index do
|
||||
div do
|
||||
render 'customer_ltv'
|
||||
end
|
||||
|
||||
column "Campaign" do |campaign|
|
||||
campaign.origin_utm_campaign
|
||||
end
|
||||
column "Medium" do |campaign|
|
||||
campaign.origin_utm_medium
|
||||
end
|
||||
column "End Date" do |campaign|
|
||||
best_in_place campaign, :end_date, as: :date, url: inplace_update_admin_ad_campaigns_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign', classes: 'ac_bip'
|
||||
end
|
||||
column "Hard Date" do |campaign|
|
||||
(campaign.end_date + 45.days).strftime('%Y-%m-%d') if campaign.end_date.present?
|
||||
end
|
||||
column "Subscribed" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.subscribed, campaign.joined))
|
||||
end
|
||||
column "Spend" do |campaign|
|
||||
best_in_place campaign, :spend, as: :input, url: inplace_update_admin_ad_campaigns_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign', display_with: Proc.new{|spend| number_to_currency(spend) }, classes: 'ac_bip'
|
||||
end
|
||||
column "CAC" do |campaign|
|
||||
number_to_currency(AdCampaignsHelper.cac(campaign)) if AdCampaignsHelper.cac(campaign) && AdCampaignsHelper.cac(campaign) > 0
|
||||
end
|
||||
column "LTV/CAC" do |campaign|
|
||||
AdCampaignsHelper.cac_divide_by_ltv(campaign)
|
||||
end
|
||||
column "Referred" do |campaign|
|
||||
best_in_place campaign, :referred, as: :input, url: inplace_update_admin_ad_campaigns_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign', display_with: Proc.new{|referred| AdCampaignsHelper.format_number(referred) }, classes: 'ac_bip'
|
||||
end
|
||||
column "Signed Up" do |campaign|
|
||||
if campaign.referred && campaign.referred > 0
|
||||
raw(AdCampaignsHelper.spacer(campaign.joined, campaign.referred))
|
||||
else
|
||||
raw("? - #{campaign.joined}")
|
||||
end
|
||||
end
|
||||
column "Downloaded" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.downloaded, campaign.joined))
|
||||
end
|
||||
column "Ran Client" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.ran_client, campaign.joined))
|
||||
end
|
||||
column "FTUE" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.ftue, campaign.joined))
|
||||
end
|
||||
column "Any Session" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.any_session, campaign.joined))
|
||||
end
|
||||
column "2+ Session" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.real_session, campaign.joined))
|
||||
end
|
||||
column "Good Session" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.good_session, campaign.joined))
|
||||
end
|
||||
column "Invited" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.invited, campaign.joined))
|
||||
end
|
||||
column "Friended" do |campaign|
|
||||
raw(AdCampaignsHelper.spacer(campaign.friended, campaign.joined))
|
||||
end
|
||||
column "Platinum" do |campaign|
|
||||
campaign.platinum
|
||||
end
|
||||
column "Gold" do |campaign|
|
||||
campaign.gold
|
||||
end
|
||||
column "Silver" do |campaign|
|
||||
campaign.silver
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
controller do
|
||||
def scoped_collection
|
||||
User.select("users.origin_utm_campaign,
|
||||
users.origin_utm_medium, COUNT(users.id) AS joined,
|
||||
COUNT(users.first_downloaded_client_at) AS downloaded,
|
||||
COUNT(users.first_subscribed_at) AS subscribed,
|
||||
COUNT(users.first_ran_client_at) AS ran_client,
|
||||
COUNT(users.first_certified_gear_at) AS ftue,
|
||||
COUNT(users.first_music_session_at) AS any_session,
|
||||
COUNT(users.first_real_music_session_at) AS real_session,
|
||||
COUNT(users.first_good_music_session_at) AS good_session,
|
||||
COUNT(users.first_invited_at) AS invited,
|
||||
COUNT(users.first_friended_at) AS friended,
|
||||
COUNT(CASE WHEN users.first_subscribed_plan_code = 'jamsubplatinum' OR users.first_subscribed_plan_code = 'jamsubplatinumyearly' THEN users.first_subscribed_plan_code END) AS platinum,
|
||||
COUNT(CASE WHEN users.first_subscribed_plan_code = 'jamsubgold' OR users.first_subscribed_plan_code = 'jamsubgoldyearly' THEN users.first_subscribed_plan_code END) AS gold,
|
||||
COUNT(CASE WHEN users.first_subscribed_plan_code = 'jamsubsilver' OR users.first_subscribed_plan_code = 'jamsubsilveryearly' THEN users.first_subscribed_plan_code END) AS silver,
|
||||
ad_campaigns.id,
|
||||
COALESCE(MAX(ad_campaigns.referred), NULL) as referred,
|
||||
COALESCE(MAX(ad_campaigns.end_date), NULL) AS end_date,
|
||||
COALESCE(MAX(ad_campaigns.spend), 0) AS spend").joins("
|
||||
LEFT JOIN ad_campaigns ON users.origin_utm_campaign = ad_campaigns.campaign
|
||||
AND users.origin_utm_medium = ad_campaigns.medium").where("
|
||||
users.origin_utm_campaign IS NOT NULL AND users.origin_utm_medium IS NOT NULL AND users.origin_utm_source = 'paid'").group("
|
||||
ad_campaigns.id, users.origin_utm_campaign, users.origin_utm_medium").order("
|
||||
users.origin_utm_campaign DESC")
|
||||
end
|
||||
|
||||
|
||||
def permitted_params
|
||||
params.permit :campaign, :medium, :_method, ad_campaign: [:spend, :referred, :end_date]
|
||||
end
|
||||
end
|
||||
|
||||
collection_action :inplace_update, method: :put do
|
||||
campaign = permitted_params[:campaign]
|
||||
medium = permitted_params[:medium]
|
||||
@ad_campaign = JamRuby::AdCampaign.where(campaign: campaign, medium: medium).first_or_create
|
||||
respond_to do |format|
|
||||
if @ad_campaign.update_attributes(permitted_params[:ad_campaign])
|
||||
format.json { head :ok }
|
||||
else
|
||||
format.json{ render :json => @ad_campaign.errors.full_messages, :status => :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# module AdCampaignsHelper
|
||||
# def campaign_brought_in_users(campaign, medium)
|
||||
# User.where(origin_utm_campaign: campaign, origin_utm_medium: medium)
|
||||
# end
|
||||
# end
|
||||
|
||||
# ActiveAdmin.register JamRuby::AdCampaign do
|
||||
# permit_params :campaign, :medium, :spend
|
||||
# end
|
||||
|
||||
# ActiveAdmin.register_page "Ad campaigns" do
|
||||
# menu parent: 'Reports'
|
||||
# content :title => "Paid Advertising Report" do
|
||||
# table_for User.select("users.origin_utm_campaign, users.origin_utm_medium, COALESCE(MAX(ad_campaigns.end_date), NULL) AS end_date, COALESCE(MAX(ad_campaigns.spend), NULL) AS spend").joins("LEFT JOIN ad_campaigns ON users.origin_utm_campaign = ad_campaigns.campaign AND users.origin_utm_medium = ad_campaigns.medium").group("ad_campaigns.id, users.origin_utm_campaign, users.origin_utm_medium") do
|
||||
# column "Campaign" do |campaign|
|
||||
# campaign.origin_utm_campaign
|
||||
# end
|
||||
# column "Medium" do |campaign|
|
||||
# campaign.origin_utm_medium
|
||||
# end
|
||||
# column "End Date" do |campaign|
|
||||
# campaign.end_date
|
||||
# end
|
||||
# column "Hard Date" do |campaign|
|
||||
# campaign.end_date + 45.days if campaign.end_date.present?
|
||||
# end
|
||||
# column "Subscribed" do |campaign|
|
||||
# end
|
||||
# column "Spend" do |campaign|
|
||||
# best_in_place campaign, :spend, as: :input, url: admin_ad_campaigns_update_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign'
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
# page_action :update, method: :put do
|
||||
# campaign = params[:campaign]
|
||||
# medium = params[:medium]
|
||||
# ad_campaign = AdCampaign.where(campaign: campaign, medium: medium).first_or_initialize
|
||||
# ad_campaign.attributes = params["ad_campaign"]
|
||||
# ad_campaign.save!
|
||||
# respond_with_bip(ad_campaign)
|
||||
# end
|
||||
# end
|
||||
|
|
@ -79,8 +79,8 @@ ActiveAdmin.register_page "Affiliate Cohorts" do
|
|||
link_to partner.partner_name, admin_affiliate_path(partner)
|
||||
end
|
||||
column 'Affiliate ID', :id
|
||||
column 'Affiliate Email', Proc.new{ | partner | partner&.partner_user&.email}
|
||||
column 'Affiliate Paypal', Proc.new{| partner | partner.paypal_id }
|
||||
column 'Affiliate Email', Proc.new{ | partner | partner.partner_user.email}
|
||||
column 'Affiliate Paypal', Proc.new{| partner | partner&.paypal_id }
|
||||
column 'All Time Users', :referral_user_count
|
||||
column 'All Time Subscribers', Proc.new{ | partner | partner.subscribed_user_referrals.size }
|
||||
column 'All Time Subscriber Conversion Rate', Proc.new{ | partner |
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
|
|||
|
||||
menu :label => 'Quarterly Reports', :parent => 'Affiliates'
|
||||
|
||||
config.sort_order = 'year desc, quarter desc, due_amount_in_cents desc'
|
||||
config.sort_order = 'due_amount_in_cents DESC'
|
||||
config.batch_actions = false
|
||||
config.clear_action_items!
|
||||
config.filters = true
|
||||
|
|
@ -14,32 +14,18 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
|
|||
filter :quarter
|
||||
filter :closed
|
||||
filter :paid
|
||||
filter :jamtracks_sold
|
||||
filter :subscriptions_count
|
||||
filter :due_amount_in_cents
|
||||
|
||||
form :partial => 'form'
|
||||
|
||||
scope("Sorted By Due Amount", default: true) { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') }
|
||||
scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.order('year desc, quarter desc, jamtracks_sold desc') }
|
||||
scope("Sorted By Subs", default: false) { |scope| scope.order('year desc, quarter desc, subscriptions_count desc') }
|
||||
scope("Sorted By Newest First") { |scope| scope.order('year desc, quarter desc, id desc') }
|
||||
scope("Any") { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') }
|
||||
|
||||
|
||||
index do
|
||||
|
||||
# default_actions # use this for all view/edit/delete links
|
||||
|
||||
column 'Year' do |oo| oo.year end
|
||||
column 'Quarter' do |oo| oo.quarter end
|
||||
column 'Partner Id' do |oo| oo.affiliate_partner.id end
|
||||
column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end
|
||||
column "Tot ($)" do |oo| sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f) end
|
||||
column "Sub ($)" do |oo| sprintf("$%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f) end
|
||||
column "Jam ($)" do |oo| sprintf("$%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f) end
|
||||
column 'JamTracks' do |oo| oo.jamtracks_sold end
|
||||
column 'Subscriptions' do |oo| oo.subscriptions_count end
|
||||
column "Due (\u00A2)" do |oo| oo.due_amount_in_cents end
|
||||
column 'JamTracks Sold' do |oo| oo.jamtracks_sold end
|
||||
column 'Paid' do |oo| oo.paid end
|
||||
column 'Closed' do |oo| oo.paid end
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ ActiveAdmin.register JamRuby::AffiliateTrafficTotal, :as => 'Affiliate Daily Sta
|
|||
# default_actions # use this for all view/edit/delete links
|
||||
|
||||
column 'Day' do |oo| oo.day end
|
||||
column 'Partner ID' do |oo| oo.affiliate_partner.id end
|
||||
column 'Partner Name' do |oo| oo.affiliate_partner.display_name end
|
||||
column 'Partner User' do |oo| link_to(oo.affiliate_partner.partner_user.name, admin_user_path(oo.affiliate_partner.partner_user.id), { :title => oo.affiliate_partner.partner_user.name }) end
|
||||
column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end
|
||||
column 'Signups' do |oo| oo.signups end
|
||||
column 'Visits' do |oo| oo.visits end
|
||||
|
||||
|
|
@ -33,16 +31,6 @@ ActiveAdmin.register JamRuby::AffiliateTrafficTotal, :as => 'Affiliate Daily Sta
|
|||
|
||||
|
||||
controller do
|
||||
def scoped_collection
|
||||
rel = end_of_association_chain
|
||||
.includes([:affiliate_partner])
|
||||
.order('day DESC')
|
||||
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
||||
qq = ['affiliate_partner_id = ?', ref_id]
|
||||
else
|
||||
qq = ['affiliate_partner_id IS NOT NULL']
|
||||
end
|
||||
@users ||= rel.where(qq)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,32 +8,27 @@ ActiveAdmin.register JamRuby::User, :as => 'Referrals' do
|
|||
config.filters = true
|
||||
|
||||
filter :affiliate_referral
|
||||
filter :email
|
||||
|
||||
## scope("Has Signups", default: true) { |scope| scope.where('visits != 0 or signups != 0').order('day desc') }
|
||||
|
||||
index do
|
||||
column 'User' do |oo| link_to(oo.name, oo.admin_url, {:title => oo.name}) end
|
||||
column 'User Email' do |oo| oo.email end
|
||||
column 'Email' do |oo| oo.email end
|
||||
column 'Created' do |oo| oo.created_at end
|
||||
column 'Partner ID' do |oo| oo.affiliate_referral.id end
|
||||
column 'Partner Name' do |oo| oo.affiliate_referral.display_name end
|
||||
column 'Partner User' do |oo| link_to(oo.affiliate_referral.partner_user.name, admin_user_path(oo.affiliate_referral.partner_user.id), { :title => oo.affiliate_referral.partner_user.name }) end
|
||||
column 'Partner' do |oo| oo.affiliate_referral.display_name end
|
||||
end
|
||||
|
||||
controller do
|
||||
|
||||
def scoped_collection
|
||||
rel = end_of_association_chain
|
||||
.includes([:affiliate_referral])
|
||||
.order('created_at DESC')
|
||||
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
||||
qq = ['affiliate_referral_id = ?', ref_id]
|
||||
else
|
||||
qq = ['affiliate_referral_id IS NOT NULL']
|
||||
def scoped_collection
|
||||
rel = end_of_association_chain
|
||||
.includes([:affiliate_referral])
|
||||
.order('created_at DESC')
|
||||
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
||||
qq = ['affiliate_referral_id = ?', ref_id]
|
||||
else
|
||||
qq = ['affiliate_referral_id IS NOT NULL']
|
||||
end
|
||||
@users ||= rel.where(qq)
|
||||
end
|
||||
@users ||= rel.where(qq)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,35 +5,19 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
|||
config.sort_order = 'referral_user_count DESC'
|
||||
config.batch_actions = false
|
||||
# config.clear_action_items!
|
||||
config.filters = true
|
||||
config.per_page = 100
|
||||
config.filters = false
|
||||
config.per_page = 50
|
||||
config.paginate = true
|
||||
|
||||
#form :partial => 'form'
|
||||
|
||||
|
||||
#filter :partner_user
|
||||
filter :partner_name
|
||||
filter :id
|
||||
filter :current_quarter_in_cents
|
||||
filter :cumulative_earnings_in_cents
|
||||
filter :jamtracks_sold
|
||||
filter :subscriptions_count
|
||||
filter :referral_user_count
|
||||
|
||||
scope("Sorted By Current Quarter", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('current_quarter_in_cents desc') }
|
||||
scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('jamtracks_sold desc') }
|
||||
scope("Sorted By Subs", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('subscriptions_count desc') }
|
||||
scope("Sorted By Signups", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
|
||||
scope("Sorted By Newest First") { |scope| scope.where('partner_user_id IS NOT NULL').order('id desc') }
|
||||
scope("Any") { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
|
||||
scope("Active", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
|
||||
scope("Unpaid") { |partner| partner.unpaid }
|
||||
|
||||
controller do
|
||||
helper 'active_admin/subscription'
|
||||
end
|
||||
|
||||
|
||||
form do |f|
|
||||
f.inputs 'Fields' do
|
||||
f.input(:partner_name, :input_html => { :maxlength => 128 })
|
||||
|
|
@ -61,47 +45,14 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
|||
column 'Code' do |oo|
|
||||
oo.id
|
||||
end
|
||||
column 'Signups' do |oo|
|
||||
column 'Referral Count' do |oo|
|
||||
oo.referral_user_count
|
||||
end
|
||||
column 'JamTracks' do |oo|
|
||||
oo.jamtracks_sold
|
||||
end
|
||||
column 'Subs' do |oo|
|
||||
oo.subscriptions_count
|
||||
end
|
||||
column 'Cum Earnings' do |oo|
|
||||
div do
|
||||
sprintf("Tot $%.2f", oo.cumulative_earnings_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Jam $%.2f", oo.jamtrack_cumulative_earnings_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Sub $%.2f", oo.subscriptions_cumulative_earnings_in_dollars)
|
||||
end
|
||||
end
|
||||
column 'Current Quarter' do |oo|
|
||||
div do
|
||||
sprintf("Tot $%.2f", oo.current_quarter_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Jam $%.2f", oo.jamtrack_current_quarter_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Sub $%.2f", oo.subscriptions_current_quarter_in_dollars)
|
||||
end
|
||||
column 'Earnings' do |oo|
|
||||
sprintf("$%.2f", oo.cumulative_earnings_in_dollars)
|
||||
end
|
||||
column 'Amount Owed' do |oo|
|
||||
div do
|
||||
sprintf("Tot $%.2f", oo.due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
div do
|
||||
sprintf("Jam $%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
div do
|
||||
sprintf("Sub $%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
column 'Pay Actions' do |oo|
|
||||
link_to('Mark Paid', mark_paid_admin_affiliate_path(oo.id), :confirm => "Mark this affiliate as PAID?") if oo.unpaid
|
||||
|
|
@ -120,15 +71,6 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
|||
row :address
|
||||
row :tax_identifier
|
||||
row :paypal_id
|
||||
row :venmo_user_id
|
||||
row :jamtracks_sold
|
||||
row :subscriptions_count
|
||||
row :cumulative_earnings_in_dollars
|
||||
row :jamtrack_cumulative_earnings_in_dollars
|
||||
row :subscriptions_cumulative_earnings_in_dollars
|
||||
row :current_quarter_in_dollars
|
||||
row :jamtrack_current_quarter_in_dollars
|
||||
row :subscriptions_current_quarter_in_dollars
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
ActiveAdmin.register JamRuby::AppFeature, as: 'App Features' do
|
||||
|
||||
menu parent: 'Misc', label: 'App Features'
|
||||
|
||||
config.sort_order = 'created_at ASC'
|
||||
config.batch_actions = false
|
||||
config.filters = false
|
||||
config.per_page = 50
|
||||
config.paginate = true
|
||||
|
||||
form do |f|
|
||||
f.inputs 'Fields' do
|
||||
f.input(:feature_type, as: :select, collection: JamRuby::AppFeature::FEATURE_TYPES)
|
||||
f.input(:handle, :input_html => { :maxlength => 1025 })
|
||||
f.input(:is_enabled, as: :boolean)
|
||||
f.input(:env, as: :select, collection: %w(production staging development))
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -3,7 +3,7 @@ ActiveAdmin.register JamRuby::GenericState, :as => 'GenericState' do
|
|||
|
||||
config.clear_action_items!
|
||||
filter :env
|
||||
permit_params :top_message, :event_page_top_logo_url, :customer_ltv, :connection_policy
|
||||
permit_params :top_message, :event_page_top_logo_url, :connection_policy
|
||||
|
||||
actions :all, :except => [:destroy]
|
||||
|
||||
|
|
|
|||
|
|
@ -23,116 +23,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
|
||||
form :partial => "form"
|
||||
|
||||
action_item :school_user, only: :index do
|
||||
link_to "Quick Add School User", add_school_user_admin_users_path
|
||||
end
|
||||
|
||||
action_item :latency, only: :show do
|
||||
link_to 'Show Latency', latency_admin_user_path(resource)
|
||||
end
|
||||
|
||||
collection_action :add_school_user, method: [:get, :post] do
|
||||
if request.post?
|
||||
@client = RecurlyClient.new
|
||||
errors = []
|
||||
user_params = params[:jam_ruby_user]
|
||||
|
||||
user_type = user_params[:user_type].strip
|
||||
school_id = user_params[:school_id].strip
|
||||
|
||||
return (render text: "Please select school") if school_id.blank?
|
||||
|
||||
first_name = user_params[:first_name].strip
|
||||
last_name = user_params[:last_name].strip
|
||||
email = user_params[:email].strip.downcase
|
||||
license_start = user_params[:license_start].strip
|
||||
license_end = user_params[:license_end].strip
|
||||
import_source = user_params[:import_source].strip
|
||||
password = SecureRandom.uuid
|
||||
|
||||
options = {
|
||||
first_name: first_name,
|
||||
last_name: last_name,
|
||||
email: email,
|
||||
license_start: license_start,
|
||||
license_end: license_end,
|
||||
import_source: import_source,
|
||||
terms_of_service: true,
|
||||
musician: true,
|
||||
skip_recaptcha: true,
|
||||
password: password,
|
||||
password_confirmation: password
|
||||
}
|
||||
options.merge!({ school_id: school_id }) if school_id.present?
|
||||
|
||||
instrument = Instrument.find('electric guitar')
|
||||
instruments = [{instrument_id: instrument.id, proficiency_level: 3, priority: 1}]
|
||||
options[:instruments] = instruments
|
||||
|
||||
parse_user_type(user_type, options)
|
||||
|
||||
@user = User.find_by_email(options[:email])
|
||||
|
||||
unless @user.nil?
|
||||
@user.user_type = user_type
|
||||
#if @user.import_source.nil?
|
||||
#TODO: do we need to have following 3 lines for an existing user?
|
||||
@user.import_source = options[:import_source]
|
||||
@user.license_start = options[:license_start]
|
||||
@user.license_end = options[:license_end]
|
||||
|
||||
if options[:student]
|
||||
@user.school_id = options[:school_id]
|
||||
@user.is_a_student = true
|
||||
elsif options[:teacher]
|
||||
@user.school = school
|
||||
if @user.teacher.nil?
|
||||
@user.teacher = Teacher.build_teacher(@user, validate_introduction: true, biography: "Empty biography", school_id: school.id)
|
||||
end
|
||||
elsif options[:platform_instructor]
|
||||
@user.is_platform_instructor = true
|
||||
end
|
||||
|
||||
if @user.save
|
||||
@client.sync_subscription(@user)
|
||||
if options[:student]
|
||||
UserMailer.school_welcome_message(@user, nil).deliver_now
|
||||
elsif options[:teacher]
|
||||
UserMailer.school_welcome_message(@user, nil).deliver_now
|
||||
elsif options[:platform_instructor]
|
||||
end
|
||||
end
|
||||
if @user.errors.any?
|
||||
flash[:error] = "Error updating User #{@user.name} #{@user.email}"
|
||||
render :add_school_user
|
||||
else
|
||||
flash[:notice] = "User #{@user.name} #{@user.email} updated successfully"
|
||||
redirect_to admin_users_path
|
||||
end
|
||||
#end
|
||||
else
|
||||
@user = User.signup(options)
|
||||
|
||||
if @user.errors.none?
|
||||
@client.sync_subscription(@user)
|
||||
puts "User #{@user.email} created"
|
||||
flash[:notice] = "User #{@user.name} #{@user.email} added successfully"
|
||||
redirect_to admin_users_path
|
||||
else
|
||||
flash[:error] = "Error adding school user"
|
||||
render :add_school_user
|
||||
end
|
||||
end
|
||||
else
|
||||
@user = User.new
|
||||
@user.import_source = 'Manual'
|
||||
end
|
||||
end
|
||||
|
||||
member_action :update_school_user, method: [:get, :put] do
|
||||
|
||||
end
|
||||
|
||||
member_action :delete_forever, :method => :get do
|
||||
resource.permanently_delete
|
||||
redirect_to :back, {notice: 'User email and login credentials have been permanently changed'}
|
||||
|
|
@ -230,28 +120,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
|
||||
end
|
||||
|
||||
member_action :latency, method: :get do
|
||||
@user = resource
|
||||
latency_url = "#{Rails.application.config.latency_data_host}/user/#{@user.id}"
|
||||
uri = URI(latency_url)
|
||||
begin
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
|
||||
req = Net::HTTP::Get.new(uri.request_uri)
|
||||
req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
||||
req["Content-Type"] = "application/json"
|
||||
|
||||
response = http.request(req)
|
||||
|
||||
render text: "404 Not Found", status: 404 if response.is_a?(Net::HTTPNotFound)
|
||||
#render json: response.body, status: 200 if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
|
||||
@user_latency = response.body
|
||||
rescue => e
|
||||
render text: e.message
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
show do |user|
|
||||
panel "Common" do
|
||||
|
|
@ -475,55 +344,35 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
panel "School" do
|
||||
div do
|
||||
attributes_table do
|
||||
row "School" do |user|
|
||||
span do
|
||||
if user.school
|
||||
link_to user.school.name, admin_school_path(user.school), target: '_blank'
|
||||
end
|
||||
end
|
||||
end
|
||||
if user.school
|
||||
row :license_start
|
||||
row :license_end
|
||||
row :is_platform_instructor
|
||||
panel "Onboarding" do
|
||||
attributes_table do
|
||||
row :onboarding_status
|
||||
row "Support Consultant" do |user|
|
||||
if user.onboarder
|
||||
link_to "#{user.onboarder.name} (#{user.onboarder.onboarding_users.count})", user.onboarder.admin_url
|
||||
else
|
||||
end
|
||||
end
|
||||
row "Signup" do
|
||||
user.created_at.to_date
|
||||
end
|
||||
row "Assigned", :onboarder_assigned_at
|
||||
row "Email 1", :onboarding_email_1_sent_at
|
||||
row "Email 2", :onboarding_email_2_sent_at
|
||||
row "Email 3", :onboarding_email_3_sent_at
|
||||
row "Email 4", :onboarding_email_4_sent_at
|
||||
row "Email 5", :onboarding_email_5_sent_at
|
||||
row "Test Session Scheduled Time", :onboarding_test_session_at
|
||||
row "When Test Session Was Requested", :onboarding_test_session_at
|
||||
row "Test Session Outcome", :onboarding_test_session_outcome
|
||||
row "Notes", :onboarding_onboarder_notes
|
||||
row "Lost Reason", :onboarding_lost_reason
|
||||
row "Lost At", :onboarding_lost_at
|
||||
row "Escalated Reason", :onboarding_escalation_reason
|
||||
row "Escalated At", :onboarding_escalated_at
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# panel "Onboarding" do
|
||||
# attributes_table do
|
||||
# row :onboarding_status
|
||||
# row "Support Consultant" do |user|
|
||||
# if user.onboarder
|
||||
# link_to "#{user.onboarder.name} (#{user.onboarder.onboarding_users.count})", user.onboarder.admin_url
|
||||
# else
|
||||
# end
|
||||
# end
|
||||
# row "Signup" do
|
||||
# user.created_at.to_date
|
||||
# end
|
||||
# row "Assigned", :onboarder_assigned_at
|
||||
# row "Email 1", :onboarding_email_1_sent_at
|
||||
# row "Email 2", :onboarding_email_2_sent_at
|
||||
# row "Email 3", :onboarding_email_3_sent_at
|
||||
# row "Email 4", :onboarding_email_4_sent_at
|
||||
# row "Email 5", :onboarding_email_5_sent_at
|
||||
# row "Test Session Scheduled Time", :onboarding_test_session_at
|
||||
# row "When Test Session Was Requested", :onboarding_test_session_at
|
||||
# row "Test Session Outcome", :onboarding_test_session_outcome
|
||||
# row "Notes", :onboarding_onboarder_notes
|
||||
# row "Lost Reason", :onboarding_lost_reason
|
||||
# row "Lost At", :onboarding_lost_at
|
||||
# row "Escalated Reason", :onboarding_escalation_reason
|
||||
# row "Escalated At", :onboarding_escalated_at
|
||||
|
||||
# end
|
||||
# end
|
||||
=begin
|
||||
|
||||
panel "Teacher Setting" do
|
||||
|
|
@ -637,15 +486,10 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
controller do
|
||||
|
||||
# this actually searches on first name, last name, and email, because of get_autocomplete_items defined below
|
||||
autocomplete :user, :email, :full => true, :display_value => :autocomplete_display_name, extra_data: [:last_jam_addr]
|
||||
autocomplete :user, :email, :full => true, :display_value => :autocomplete_display_name
|
||||
|
||||
def get_autocomplete_items(parameters)
|
||||
term = parameters[:term]
|
||||
if term.include?('@')
|
||||
User.select("email, first_name, last_name, id, last_jam_addr").where(["email = ?", term]).limit(5)
|
||||
else
|
||||
User.select("email, first_name, last_name, id, last_jam_addr").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{term}%", "%#{term}%", "%#{term}%"]).limit(40)
|
||||
end
|
||||
User.select("email, first_name, last_name, id").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -667,6 +511,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
@user = resource
|
||||
@user.email = params[:jam_ruby_user][:email]
|
||||
@user.admin = params[:jam_ruby_user][:admin]
|
||||
@user.is_onboarder = params[:jam_ruby_user][:is_onboarder]
|
||||
@user.subscribe_email = params[:jam_ruby_user][:subscribe_email]
|
||||
@user.musician = params[:jam_ruby_user][:musician]
|
||||
@user.first_name = params[:jam_ruby_user][:first_name]
|
||||
|
|
@ -703,97 +548,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
redirect_to edit_admin_user_path(@user)
|
||||
|
||||
end
|
||||
|
||||
def user_latency_recommendation
|
||||
recommendation_params = params[:latency_recommendation]
|
||||
|
||||
offset = recommendation_params[:offset].blank?? 0 : recommendation_params[:offset]
|
||||
limit = recommendation_params[:limit].blank?? 20 : recommendation_params[:limit]
|
||||
|
||||
is_valid = [
|
||||
recommendation_params[:my_user_id],
|
||||
recommendation_params[:my_public_ip]
|
||||
].all?{ |param|
|
||||
param.present?
|
||||
}
|
||||
|
||||
if is_valid
|
||||
instruments = []
|
||||
instruments << recommendation_params[:instruments_beginner].reject(&:blank?).map{|i| { id: i, proficiency: 1} }
|
||||
instruments << recommendation_params[:instruments_advanced].reject(&:blank?).map{|i| { id: i, proficiency: 2} }
|
||||
instruments << recommendation_params[:instruments_expert].reject(&:blank?).map{|i| { id: i, proficiency: 3} }
|
||||
instruments.flatten!
|
||||
genres = recommendation_params[:genres].reject(&:blank?)
|
||||
wifi = recommendation_params[:wifi]
|
||||
max_latency = recommendation_params[:max_latency]
|
||||
|
||||
data = {
|
||||
my_user_id: recommendation_params[:my_user_id],
|
||||
my_public_ip: recommendation_params[:my_public_ip],
|
||||
offset: offset,
|
||||
limit: limit
|
||||
}
|
||||
|
||||
data.merge!({query: recommendation_params[:query]}) unless recommendation_params[:query].blank?
|
||||
data.merge!({instruments: instruments}) unless instruments.empty?
|
||||
data.merge!({genres: genres}) unless genres.empty?
|
||||
data.merge!({wifi: wifi}) if %w(true false).include?(wifi)
|
||||
data.merge!({max_latency: max_latency}) unless max_latency.blank?
|
||||
|
||||
latency_url = "#{Rails.application.config.latency_data_host}/recommendations"
|
||||
uri = URI(latency_url)
|
||||
|
||||
begin
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.read_timeout = 5
|
||||
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
|
||||
request = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
|
||||
request.body = data.to_json
|
||||
request["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
||||
response = http.request(request)
|
||||
@latency_recommendation = response.body
|
||||
rescue => exception
|
||||
render text: exception.message
|
||||
end
|
||||
|
||||
else
|
||||
flash[:error] = 'Please provide all required fields'
|
||||
redirect_to admin_latency_recommendation_path
|
||||
end
|
||||
end
|
||||
|
||||
def user_latencies
|
||||
latency_params = params[:latencies]
|
||||
latency_url = "#{Rails.application.config.latency_data_host}/user_latencies"
|
||||
uri = URI(latency_url)
|
||||
if not ([latency_params[:my_user_id], latency_params[:my_public_ip], latency_params[:user_1_id]]).any?{|param| param.blank? }
|
||||
user_ids = [latency_params[:user_1_id]]
|
||||
user_ids.push(latency_params[:user_2_id]) unless latency_params[:user_2_id].blank?
|
||||
user_ids.push(latency_params[:user_3_id]) unless latency_params[:user_3_id].blank?
|
||||
user_ids.push(latency_params[:user_4_id]) unless latency_params[:user_4_id].blank?
|
||||
user_ids.push(latency_params[:user_5_id]) unless latency_params[:user_5_id].blank?
|
||||
begin
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.read_timeout = 5
|
||||
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
|
||||
request = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
|
||||
request.body = {
|
||||
my_user_id: latency_params[:my_user_id],
|
||||
my_public_ip: latency_params[:my_public_ip],
|
||||
users: user_ids
|
||||
}.to_json
|
||||
request["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
|
||||
response = http.request(request)
|
||||
@user_latencies = response.body
|
||||
#render text: JSON.pretty_generate(@user_latencies)
|
||||
rescue => e
|
||||
render text: e.message
|
||||
end
|
||||
else
|
||||
flash[:error] = 'Please provide all required fields'
|
||||
redirect_to admin_latency_between_users_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -17,14 +17,6 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
|||
|
||||
filter :jam_track
|
||||
|
||||
controller do
|
||||
def create
|
||||
jt_params = params[:jam_ruby_jam_track_right]
|
||||
jt_params[:jam_track] =JamRuby::JamTrack.where("id=?", jt_params[:jam_track_id_val]).first # jt_params[:jam_track_id_val]
|
||||
jt_params[:user] = JamRuby::User.where("id=?", jt_params[:user_id_val]).first # jt_params[:user_id_val]
|
||||
create!
|
||||
end
|
||||
end
|
||||
index do
|
||||
actions
|
||||
|
||||
|
|
@ -55,14 +47,9 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
|||
|
||||
form do |f|
|
||||
f.inputs 'New Jam Track Right' do
|
||||
#f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
|
||||
f.input :jam_track_id_val, :required=>true, :as => :hidden
|
||||
|
||||
f.input :jam_track, :required=>true, :as => :autocomplete, :url => autocomplete_jam_track_name_admin_jam_tracks_path, hint: 'Select a jamtrack to give to this user'
|
||||
#f.input :user, :required=>true, collection: User.all, include_blank: false
|
||||
f.input :user_id_val, :required=>true, :as => :hidden
|
||||
f.input :user, :required=>true, :as => :autocomplete, :url => autocomplete_user_email_admin_users_path, hint: 'Give a free jamtrack to this user'
|
||||
f.input :can_download, :required => true, as: :boolean, :input_html => { :checked => 'checked' }
|
||||
f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
|
||||
f.input :user, :required=>true, collection: User.all, include_blank: false
|
||||
f.input :can_download, :required => true, as: :boolean
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
||||
|
||||
collection_action :autocomplete_jam_track_name, :method => :get
|
||||
|
||||
menu :label => 'JamTracks', :parent => 'JamTracks'
|
||||
|
||||
config.sort_order = 'name_asc'
|
||||
|
|
@ -21,19 +19,6 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
|||
|
||||
form :partial => 'form'
|
||||
|
||||
|
||||
controller do
|
||||
|
||||
# this actually searches on first name, last name, and email, because of get_autocomplete_items defined below
|
||||
autocomplete :jam_track, :name, :full => true, :display_value => :autocomplete_display_name
|
||||
|
||||
def get_autocomplete_items(parameters)
|
||||
JamTrack.select("name, original_artist, id").where(["name ILIKE ? OR original_artist ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
index do
|
||||
|
||||
# actions # use this for all view/edit/delete links
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
class Spacer
|
||||
def self.spacer(val, row)
|
||||
|
||||
percentage = ((val * 100) / row.total.to_f).round(1).to_s
|
||||
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
|
||||
end
|
||||
end
|
||||
=begin
|
||||
select
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
|
||||
select first_name, last_name, email
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
AND first_music_session_at is NULL;
|
||||
|
||||
=end
|
||||
|
||||
ActiveAdmin.register_page "Jammers Subscription Cohorts" do
|
||||
menu :parent => 'Reports'
|
||||
|
||||
content :title => "Jammers Subscription Cohorts" do
|
||||
|
||||
filter_type = params[:filter_type] || 'All'
|
||||
filter_campaign = params[:filter_campaign]
|
||||
filter_campaign_id = params[:filter_campaign_id]
|
||||
filter_ad_set = params[:filter_ad_set]
|
||||
filter_ad_name = params[:filter_ad_name]
|
||||
|
||||
campaigns = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_utm_campaign).compact.sort
|
||||
campaign_ids = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_id).compact.sort
|
||||
ad_sets = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_term).compact.sort
|
||||
ad_names = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_content).compact.sort
|
||||
|
||||
div style: "margin-bottom: 20px; padding: 10px; background-color: #f4f4f4; border-radius: 4px;" do
|
||||
form action: admin_jammers_subscription_cohorts_path, method: :get do
|
||||
span "Source: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_type', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: 'All', selected: filter_type == 'All'
|
||||
option "Organic", value: 'Organic', selected: filter_type == 'Organic'
|
||||
option "Advertising", value: 'Advertising', selected: filter_type == 'Advertising'
|
||||
end
|
||||
|
||||
if filter_type == 'Advertising'
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Campaign Name: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_campaign', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_campaign == 'NULL'
|
||||
campaigns.each do |c|
|
||||
option c, value: c, selected: filter_campaign == c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Campaign ID: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_campaign_id', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_campaign_id == 'NULL'
|
||||
campaign_ids.each do |c|
|
||||
option c, value: c, selected: filter_campaign_id == c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Ad Set: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_ad_set', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_ad_set == 'NULL'
|
||||
ad_sets.each do |c|
|
||||
option c, value: c, selected: filter_ad_set == c
|
||||
end
|
||||
end
|
||||
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Ad Name: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_ad_name', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_ad_name == 'NULL'
|
||||
ad_names.each do |c|
|
||||
option c, value: c, selected: filter_ad_name == c
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
noscript { input type: :submit, value: "Filter" }
|
||||
end
|
||||
end
|
||||
|
||||
h2 "Users Grouped By Month as Paying Subscribers"
|
||||
|
||||
query = User.select(%Q{date_trunc('month', users.created_at) as month,
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed,
|
||||
count(first_played_jamtrack_at) as played_jamtrack
|
||||
})
|
||||
.joins(%Q{LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
j.created_at
|
||||
FROM
|
||||
jam_track_rights as j
|
||||
WHERE
|
||||
j.user_id = users.id
|
||||
ORDER BY
|
||||
j.created_at
|
||||
LIMIT 1 -- Select only that single row
|
||||
) j ON TRUE })
|
||||
|
||||
if filter_type == 'Organic'
|
||||
query = query.where("users.origin_utm_source = 'organic'")
|
||||
elsif filter_type == 'Advertising'
|
||||
query = query.where("origin_utm_medium = 'cpc'")
|
||||
|
||||
if filter_campaign.present?
|
||||
if filter_campaign == 'NULL'
|
||||
query = query.where("users.origin_utm_campaign IS NULL")
|
||||
elsif filter_campaign != 'All'
|
||||
query = query.where("users.origin_utm_campaign = ?", filter_campaign)
|
||||
end
|
||||
end
|
||||
|
||||
if filter_campaign_id.present?
|
||||
if filter_campaign_id == 'NULL'
|
||||
query = query.where("users.origin_id IS NULL")
|
||||
elsif filter_campaign_id != 'All'
|
||||
query = query.where("users.origin_id = ?", filter_campaign_id)
|
||||
end
|
||||
end
|
||||
|
||||
if filter_ad_set.present?
|
||||
if filter_ad_set == 'NULL'
|
||||
query = query.where("users.origin_term IS NULL")
|
||||
elsif filter_ad_set != 'All'
|
||||
query = query.where("users.origin_term = ?", filter_ad_set)
|
||||
end
|
||||
end
|
||||
|
||||
if filter_ad_name.present?
|
||||
if filter_ad_name == 'NULL'
|
||||
query = query.where("users.origin_content IS NULL")
|
||||
elsif filter_ad_name != 'All'
|
||||
query = query.where("users.origin_content = ?", filter_ad_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table_for query.group("date_trunc('month', users.created_at)")
|
||||
.where("j.created_at IS NULL OR (j.created_at - users.created_at) >= INTERVAL '2 hours'")
|
||||
.order("date_trunc('month', users.created_at) DESC") do |row|
|
||||
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
|
||||
column "Total", :total
|
||||
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
|
||||
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
|
||||
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
|
||||
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
|
||||
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
|
||||
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
|
||||
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
|
||||
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
|
||||
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
|
||||
column "Played JT", Proc.new { |user| raw(Spacer.spacer(user.played_jamtrack, user)) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
class Spacer
|
||||
def self.spacer(val, row)
|
||||
|
||||
percentage = ((val * 100) / row.total.to_f).round(1).to_s
|
||||
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
|
||||
end
|
||||
end
|
||||
=begin
|
||||
select
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
|
||||
select first_name, last_name, email
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
AND first_music_session_at is NULL;
|
||||
|
||||
=end
|
||||
|
||||
ActiveAdmin.register_page "JamTrack Subscription Cohorts" do
|
||||
menu :parent => 'Reports'
|
||||
|
||||
content :title => "JamTrack Subscription Cohorts" do
|
||||
h2 "Users Grouped By Month as Paying Subscribers"
|
||||
table_for User.select(%Q{date_trunc('month', users.created_at) as month,
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed,
|
||||
count(first_played_jamtrack_at) as played_jamtrack
|
||||
})
|
||||
.joins(%Q{INNER JOIN LATERAL (
|
||||
SELECT
|
||||
j.created_at
|
||||
FROM
|
||||
jam_track_rights as j
|
||||
WHERE
|
||||
j.user_id = users.id
|
||||
ORDER BY
|
||||
j.created_at
|
||||
LIMIT 1 -- Select only that single row
|
||||
) j ON (j.created_at - users.created_at) < INTERVAL '2 hours' })
|
||||
.group("date_trunc('month', users.created_at)").order("date_trunc('month', users.created_at) DESC") do |row|
|
||||
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
|
||||
column "Total", :total
|
||||
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
|
||||
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
|
||||
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
|
||||
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
|
||||
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
|
||||
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
|
||||
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
|
||||
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
|
||||
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
|
||||
column "Played JT", Proc.new { |user| raw(Spacer.spacer(user.played_jamtrack, user)) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
class Spacer
|
||||
def self.spacer(val, row)
|
||||
|
||||
percentage = ((val * 100) / row.total.to_f).round(1).to_s
|
||||
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
|
||||
end
|
||||
end
|
||||
|
||||
ActiveAdmin.register_page "Subscription Cohorts" do
|
||||
menu :parent => 'Reports'
|
||||
|
||||
|
||||
content :title => "Subscription Cohorts" do
|
||||
h2 "Users Grouped By Month as Paying Subscribers"
|
||||
table_for User.select(%Q{date_trunc('month', created_at) as month,
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(recurly_subscription_id) as subscribed
|
||||
}).group("date_trunc('month', created_at)").order("date_trunc('month', created_at) DESC") do |row|
|
||||
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
|
||||
column "Total", :total
|
||||
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
|
||||
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
|
||||
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
|
||||
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
|
||||
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
|
||||
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
|
||||
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
|
||||
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
|
||||
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
ActiveAdmin.register_page "Latency Between Users" do
|
||||
menu parent: 'Users'
|
||||
|
||||
content :title => "Latency Between Users" do
|
||||
render 'admin/users/users_latency_form'
|
||||
end
|
||||
end
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
ActiveAdmin.register_page "Latency Recommendation" do
|
||||
menu parent: 'Users'
|
||||
|
||||
content :title => "Latency Recommentation" do
|
||||
render 'admin/users/latency_recommendation_form'
|
||||
end
|
||||
end
|
||||
|
|
@ -6,18 +6,15 @@ ActiveAdmin.register JamRuby::User, :as => 'UserSource' do
|
|||
config.batch_actions = false
|
||||
config.clear_action_items!
|
||||
config.filters = false
|
||||
config.per_page = 250
|
||||
|
||||
scope("Paid", default: true) { |scope| scope.unscoped.where(:origin_utm_medium => 'cpc').order('created_at desc') }
|
||||
scope("Inorganic Source") { |scope| scope.unscoped.where("origin_utm_source != 'organic' OR origin_utm_source IS NULL").order('created_at desc') }
|
||||
scope("Include Organic") { |scope| scope.unscoped.order('created_at desc') }
|
||||
scope("Most Recent First", default: true) { |scope| scope.unscoped.order('created_at desc')}
|
||||
|
||||
index do
|
||||
column "Email" do |user|
|
||||
user.email
|
||||
end
|
||||
column "Signup (CST)" do |user|
|
||||
user.created_at.in_time_zone("Central Time (US & Canada)")
|
||||
column "Bought TestDrive" do |user|
|
||||
!user.most_recent_test_drive_purchase.nil? ? "Yes" : "No"
|
||||
end
|
||||
column "UTM Source" do |user|
|
||||
user.origin_utm_source
|
||||
|
|
@ -28,23 +25,8 @@ ActiveAdmin.register JamRuby::User, :as => 'UserSource' do
|
|||
column "UTM Campaign" do |user|
|
||||
user.origin_utm_campaign
|
||||
end
|
||||
column "UTM ID" do |user|
|
||||
user.origin_id
|
||||
end
|
||||
column "UTM Term" do |user|
|
||||
user.origin_term
|
||||
end
|
||||
column "UTM Content" do |user|
|
||||
user.origin_content
|
||||
end
|
||||
column "Referrer" do |user|
|
||||
user.origin_referrer
|
||||
end
|
||||
column "FB Click ID" do |user|
|
||||
user.facebook_click_id
|
||||
end
|
||||
column "FB Browser ID" do |user|
|
||||
user.facebook_browser_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,11 +13,8 @@
|
|||
// //= require autocomplete-rails
|
||||
//= require base
|
||||
//= require_tree .
|
||||
//= require best_in_place.jquery-ui
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
jQuery(".best_in_place").best_in_place();
|
||||
$.datepicker.setDefaults({
|
||||
dateFormat: 'yy-mm-dd',
|
||||
});
|
||||
jQuery(".best_in_place").best_in_place()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
jQuery(".ac_bip").bind("ajax:success", function(){ window.location.reload(); });
|
||||
})
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
function intToIP(int) {
|
||||
var part1 = int & 255;
|
||||
var part2 = ((int >> 8) & 255);
|
||||
var part3 = ((int >> 16) & 255);
|
||||
var part4 = ((int >> 24) & 255);
|
||||
|
||||
return part4 + "." + part3 + "." + part2 + "." + part1;
|
||||
}
|
||||
|
||||
function handleJamTrackRightsForm() {
|
||||
var $jamTrackRights = $('form#new_jam_ruby_jam_track_right');
|
||||
var $jamTrack = $jamTrackRights.find('#jam_ruby_jam_track_right_jam_track_id');
|
||||
var $jamTrackVal = $jamTrackRights.find('#jam_ruby_jam_track_right_jam_track_id_val')
|
||||
|
||||
var $user = $jamTrackRights.find('#jam_ruby_jam_track_right_user_id');
|
||||
var $userVal = $jamTrackRights.find('#jam_ruby_jam_track_right_user_id_val');
|
||||
$jamTrack.on('change', function(){
|
||||
console.log("change jam track");
|
||||
});
|
||||
|
||||
/**
|
||||
$user.on('change', function(){
|
||||
console.log("change user");
|
||||
});
|
||||
|
||||
$jamTrack.on('focus', function(){
|
||||
$userVal.val('')
|
||||
});*/
|
||||
|
||||
$jamTrack.bind('railsAutocomplete.select', function(event, data){
|
||||
$jamTrackVal.val('');
|
||||
$jamTrackVal.val(data.item.id);
|
||||
console.log("jam track selected with id " + data.item.id);
|
||||
});
|
||||
|
||||
$user.bind('railsAutocomplete.select', function(event, data){
|
||||
$userVal.val('');
|
||||
$userVal.val(data.item.id);
|
||||
console.log("user selected with id " + data.item.id);
|
||||
});
|
||||
}
|
||||
function handleUserLatencyForm(){
|
||||
var $userLatenciesForm = $('form#user_latencies_form');
|
||||
var $latenciesMyUser = $userLatenciesForm.find('#latencies_my_user');
|
||||
var $latenciesMyUserId = $userLatenciesForm.find('#latencies_my_user_id');
|
||||
var $latenciesMyPublicIp = $userLatenciesForm.find('#latencies_my_public_ip');
|
||||
|
||||
$latenciesMyUser.on('focus', function(){
|
||||
$latenciesMyUserId.val('')
|
||||
});
|
||||
|
||||
$latenciesMyUser.bind('railsAutocomplete.select', function(event, data){
|
||||
$latenciesMyUserId.val('');
|
||||
$latenciesMyPublicIp.val('');
|
||||
if(data.item.last_jam_addr){
|
||||
var ipAddr = intToIP(data.item.last_jam_addr);
|
||||
$latenciesMyPublicIp.val(ipAddr);
|
||||
}
|
||||
$latenciesMyUserId.val(data.item.id);
|
||||
});
|
||||
|
||||
$userLatenciesForm.find('#latencies_user_1').bind('railsAutocomplete.select', function(event, data){
|
||||
$userLatenciesForm.find('#latencies_user_1_id').val(data.item.id);
|
||||
});
|
||||
|
||||
$userLatenciesForm.find('#latencies_user_2').bind('railsAutocomplete.select', function(event, data){
|
||||
$userLatenciesForm.find('#latencies_user_2_id').val(data.item.id);
|
||||
});
|
||||
|
||||
$userLatenciesForm.find('#latencies_user_3').bind('railsAutocomplete.select', function(event, data){
|
||||
$userLatenciesForm.find('#latencies_user_3_id').val(data.item.id);
|
||||
});
|
||||
|
||||
$userLatenciesForm.find('#latencies_user_4').bind('railsAutocomplete.select', function(event, data){
|
||||
$userLatenciesForm.find('#latencies_user_4_id').val(data.item.id);
|
||||
});
|
||||
|
||||
$userLatenciesForm.find('#latencies_user_5').bind('railsAutocomplete.select', function(event, data){
|
||||
$userLatenciesForm.find('#latencies_user_5_id').val(data.item.id);
|
||||
});
|
||||
}
|
||||
|
||||
function handleLatencyRecommendationForm(){
|
||||
var $latencyRecommendationForm = $('form#latency_recommendation_form');
|
||||
var $latenciesMyUser = $latencyRecommendationForm.find('#latency_recommendation_my_user');
|
||||
var $latenciesMyUserId = $latencyRecommendationForm.find('#latency_recommendation_my_user_id');
|
||||
var $latenciesMyPublicIp = $latencyRecommendationForm.find('#latency_recommendation_my_public_ip');
|
||||
|
||||
$latenciesMyUser.on('focus', function(){
|
||||
$latenciesMyUserId.val('')
|
||||
});
|
||||
|
||||
$latenciesMyUser.bind('railsAutocomplete.select', function(event, data){
|
||||
$latenciesMyUserId.val('');
|
||||
$latenciesMyPublicIp.val('');
|
||||
if(data.item.last_jam_addr){
|
||||
var ipAddr = intToIP(data.item.last_jam_addr);
|
||||
$latenciesMyPublicIp.val(ipAddr);
|
||||
}
|
||||
$latenciesMyUserId.val(data.item.id);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
handleUserLatencyForm();
|
||||
handleLatencyRecommendationForm();
|
||||
handleJamTrackRightsForm();
|
||||
});
|
||||
|
|
@ -2,97 +2,49 @@ class ArsesController < ApplicationController
|
|||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
if params[:code] != Rails.application.config.data_dump_code
|
||||
render :json => {error: "Unauthorized"}, :status => 401
|
||||
return
|
||||
end
|
||||
|
||||
@arses = JamRuby::Ars.all
|
||||
render :json => @arses
|
||||
end
|
||||
|
||||
def update
|
||||
if params[:code] != Rails.application.config.data_dump_code
|
||||
render :json => {error: "Unauthorized"}, :status => 401
|
||||
return
|
||||
end
|
||||
|
||||
begin
|
||||
# Primary ID lookup
|
||||
@ars = JamRuby::Ars.find_by_id(params[:id])
|
||||
|
||||
# Explicit secondary lookups if primary ID fails
|
||||
@ars ||= JamRuby::Ars.find_by_id_int(params[:id_int]) if params[:id_int]
|
||||
@ars ||= JamRuby::Ars.find_by_name(params[:name]) if params[:name]
|
||||
|
||||
if @ars.nil?
|
||||
render :json => {error: "Not Found"}, :status => 404
|
||||
return
|
||||
end
|
||||
|
||||
allowed = [:password, :username, :active, :beta, :name, :provider, :id_int, :ip, :port, :continent, :country, :city, :subdivision, :latitude, :longitude]
|
||||
|
||||
update_hash = {}
|
||||
allowed.each do |attr|
|
||||
update_hash[attr] = params[attr] if params.has_key?(attr)
|
||||
end
|
||||
|
||||
if @ars.update_attributes(update_hash, as: :admin)
|
||||
render :json => @ars, :status => :ok
|
||||
else
|
||||
render :json => @ars.errors, :status => :unprocessable_entity
|
||||
end
|
||||
rescue => e
|
||||
render :json => {error: e.message, backtrace: e.backtrace.first(5)}, :status => 500
|
||||
end
|
||||
end
|
||||
|
||||
# create or update a client_artifact row
|
||||
def get_or_create
|
||||
begin
|
||||
name = params[:name]
|
||||
provider = params[:provider]
|
||||
active = params[:active]
|
||||
beta = params.has_key?(:beta) ? params[:beta] : true
|
||||
ip = params[:ip]
|
||||
username = params[:username]
|
||||
password = params[:password]
|
||||
topology = params[:topology]
|
||||
ars_id = params[:ars_id]
|
||||
name = params[:name]
|
||||
provider = params[:provider]
|
||||
active = params[:active]
|
||||
ip = params[:ip]
|
||||
username = params[:username]
|
||||
password = params[:password]
|
||||
topology = params[:topology]
|
||||
ars_id = params[:ars_id]
|
||||
puts "TOPOLOGY #{topology}"
|
||||
|
||||
# Explicit field-based lookups
|
||||
ars = nil
|
||||
ars = JamRuby::Ars.find_by_id_int(ars_id) if ars_id
|
||||
ars ||= JamRuby::Ars.find_by_name(name) if name
|
||||
|
||||
if ars.nil?
|
||||
ars = JamRuby::Ars.new
|
||||
ars.name = name
|
||||
end
|
||||
|
||||
ars.id_int = ars_id if !ars_id.nil?
|
||||
ars.provider = provider
|
||||
ars.active = active
|
||||
ars.beta = params[:beta]
|
||||
ars.beta = beta
|
||||
ars.ip = ip
|
||||
ars.password = password
|
||||
ars.username = username
|
||||
if topology
|
||||
ars.city = topology['city']
|
||||
ars.country = topology['country']
|
||||
ars.continent = topology['continent']
|
||||
ars.latitude = topology['latitude']
|
||||
ars.longitude = topology['longitude']
|
||||
ars.subdivision = topology['subdivision']
|
||||
end
|
||||
ars.save!
|
||||
|
||||
@ars = ars
|
||||
render :json => {id_int: @ars.id_int, id: @ars.id, name: @ars.name, provider: @ars.provider, active: @ars.active, beta: @ars.beta, ip: @ars.ip}, :status => :ok
|
||||
rescue => e
|
||||
render :json => {error: e.message, backtrace: e.backtrace.first(5)}, :status => 500
|
||||
if ars_id
|
||||
ars = Ars.find_by_id_int(ars_id)
|
||||
end
|
||||
if ars.nil?
|
||||
ars = Ars.new
|
||||
ars.name = name
|
||||
end
|
||||
|
||||
ars.provider = provider
|
||||
ars.active = active
|
||||
ars.ip = ip
|
||||
ars.password = password
|
||||
ars.username = username
|
||||
if topology
|
||||
ars.city = topology['city']
|
||||
ars.country = topology['country']
|
||||
ars.continent = topology['continent']
|
||||
ars.latitude = topology['latitude']
|
||||
ars.longitude = topology['longitude']
|
||||
ars.subdivision = topology['subdivision']
|
||||
end
|
||||
ars.save
|
||||
|
||||
@ars = ars
|
||||
unless @ars.errors.any?
|
||||
@ars = Ars.find_by_name(name)
|
||||
render :json => {id_int: @ars.id_int, id: @ars.id, name: @ars.name, provider: @ars.provider, active: @ars.active, ip: @ars.ip}, :status => :ok
|
||||
else
|
||||
response.status = :unprocessable_entity
|
||||
respond_with @ars
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -112,19 +112,6 @@ class Cohort < ActiveRecord::Base
|
|||
def self.cohort_users(cohort)
|
||||
User.where(created_at: cohort.group_start..cohort.group_end)
|
||||
end
|
||||
=begin
|
||||
SELECT played.user_id FROM
|
||||
(SELECT user_id, COUNT(*) cnt FROM music_sessions_user_history msuh1
|
||||
WHERE
|
||||
msuh1.created_at >= '2024-11-01' AND
|
||||
msuh1.created_at <= '202' AND
|
||||
EXTRACT(EPOCH FROM (msuh1.session_removed_at - msuh1.created_at)) >= 900 AND
|
||||
(SELECT COUNT(*) FROM music_sessions_user_history msuh2
|
||||
WHERE msuh1.music_session_id = msuh2.music_session_id
|
||||
) > 1
|
||||
GROUP BY user_id
|
||||
) played
|
||||
=end
|
||||
|
||||
def _played_online_subquery(constraint)
|
||||
where = if constraint.is_a?(Range)
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
<%= label_tag :customer_ltv, 'Customer LTV : $' %>
|
||||
<%= best_in_place GenericState.singleton, :customer_ltv, :as => :input, url: "#{ENV['RAILS_RELATIVE_URL_ROOT']}/admin/generic_states/#{GenericState.singleton.id}", place_holder: "---", :ok_button => 'Save', :cancel_button => 'Cancel', classes: 'ac_bip' %>
|
||||
<br />
|
||||
<br />
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
= f.inputs "Details" do
|
||||
= f.input :email, label: 'Email'
|
||||
= f.input :admin
|
||||
= f.input :is_onboarder, label: 'Is Support Consultant'
|
||||
= f.input :subscribe_email, label: 'Subscribed to Emails?'
|
||||
= f.input :is_platform_instructor, label: 'Is Platform Instructor?'
|
||||
= f.input :gifted_jamtracks, label: 'JamTrack Credits'
|
||||
|
|
@ -10,8 +11,6 @@
|
|||
= f.input :city
|
||||
= f.input :state
|
||||
= f.input :musician
|
||||
= f.input :beta
|
||||
= f.input :use_video_conferencing_server
|
||||
= f.inputs "Gear Mods" do
|
||||
= f.input :show_frame_options, as: :boolean
|
||||
= f.inputs "Do Not Shows" do
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
<%= semantic_form_for 'latency_recommendation', url: user_latency_recommendation_admin_users_path, html: {id: 'latency_recommendation_form'} do |f| %>
|
||||
<%= f.inputs :name => 'Select user', :class => 'inputs' do %>
|
||||
<%= f.input :my_user, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'My user name/email' %>
|
||||
<%= f.input :my_user_id, as: :hidden %>
|
||||
<%= f.input :my_public_ip, label: 'My user public IP' %>
|
||||
<% end %>
|
||||
<%= f.inputs :name => 'Query parameters', :class => 'inputs' do %>
|
||||
<%= f.input :query, required: false %>
|
||||
<%= f.input :instruments_beginner, collection: JamRuby::Instrument.all, input_html: { multiple: true }, required: false %>
|
||||
<%= f.input :instruments_advanced, collection: JamRuby::Instrument.all, input_html: { multiple: true }, required: false %>
|
||||
<%= f.input :instruments_expert, collection: JamRuby::Instrument.all, input_html: { multiple: true }, required: false %>
|
||||
<%= f.input :genres, as: :select, collection: JamRuby::Genre.all, input_html: { multiple: true }, required: false %>
|
||||
<%= f.input :wifi, as: :select, collection: {'Any': 'any', 'Yes': true, 'No': false }, required: false %>
|
||||
<%= f.input :max_latency, required: false %>
|
||||
<%= f.input :offset, input_html: { value: 0 } %>
|
||||
<%= f.input :limit, input_html: { value: 20 } %>
|
||||
<% end %>
|
||||
<%= f.actions do %>
|
||||
<%= f.action :submit, :as => :button, label: 'Submit' %>
|
||||
<%= f.action :cancel, :as => :link, label: 'Cancel' %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<%= semantic_form_for 'latencies', url: user_latencies_admin_users_path, html: {id: 'user_latencies_form'} do |f| %>
|
||||
<%= f.inputs :name => 'Select user', :class => 'inputs' do %>
|
||||
<%= f.input :my_user, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'My user name/email' %>
|
||||
<%= f.input :my_user_id, as: :hidden %>
|
||||
<%= f.input :my_public_ip, label: 'My user public IP' %>
|
||||
<% end %>
|
||||
<%= f.inputs :name => 'Select other users', :class => 'inputs' do %>
|
||||
<%= f.input :user_1, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 1' %>
|
||||
<%= f.input :user_1_id, as: :hidden %>
|
||||
<%= f.input :user_2, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 2', required: false %>
|
||||
<%= f.input :user_2_id, as: :hidden %>
|
||||
<%= f.input :user_3, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 3', required: false %>
|
||||
<%= f.input :user_3_id, as: :hidden %>
|
||||
<%= f.input :user_4, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 4', required: false %>
|
||||
<%= f.input :user_4_id, as: :hidden %>
|
||||
<%= f.input :user_5, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 5', required: false %>
|
||||
<%= f.input :user_5_id, as: :hidden %>
|
||||
<% end %>
|
||||
<%= f.actions do %>
|
||||
<%= f.action :submit, :as => :button, label: 'Submit' %>
|
||||
<%= f.action :cancel, :as => :link, label: 'Cancel' %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
= semantic_form_for([:admin_users, @user], builder: ActiveAdmin::FormBuilder, :url => @user.new_record? ? add_school_user_admin_users_path : "/admin/users/#{@user.id}/add_school_user") do |f|
|
||||
= f.inputs "Details" do
|
||||
= f.input :email, label: 'Email', required: true
|
||||
= f.input :first_name, required: true
|
||||
= f.input :last_name, required: true
|
||||
= f.input :license_start, as: :datepicker, required: true
|
||||
= f.input :license_end, as: :datepicker, required: true
|
||||
= f.input :import_source, required: true
|
||||
= f.input :school_id, as: :select, collection: School.all, required: true
|
||||
= f.input :user_type, as: :select, collection: ['Student', 'Student Instructor', 'Platform Instructor'], include_blank: false, required: true
|
||||
= f.actions
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<h2><%= @user.name %></h2>
|
||||
<pre><%= debug @user_latency -%></pre>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<pre><%= JSON.pretty_generate(JSON.parse(@user_latencies)) -%></pre>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<pre><%= JSON.pretty_generate(JSON.parse(@latency_recommendation)) -%></pre>
|
||||
|
|
@ -1 +0,0 @@
|
|||
BUNDLE_GEMFILE=Gemfile.alt RAILS_ENV=development LOCAL_DEV=1 MODERN_OS=1 JAM_RUBY_VERSION=2.4.1 bundle _1.17.3_ exec rails server -b 0.0.0.0 -p 3333
|
||||
|
|
@ -131,7 +131,7 @@ module JamAdmin
|
|||
config.email_smtp_starttls_auto = true
|
||||
|
||||
config.verify_email_enabled = false
|
||||
config.musician_count = '300,000+'
|
||||
config.musician_count = '200,000+'
|
||||
config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398'
|
||||
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'
|
||||
|
||||
|
|
@ -169,8 +169,5 @@ module JamAdmin
|
|||
config.download_tracker_day_range = 30
|
||||
config.max_user_ip_address = 10
|
||||
config.max_multiple_users_same_ip = 2
|
||||
|
||||
config.latency_data_host = "https://latency-production.naas.jamkazam.com"
|
||||
config.latency_data_host_auth_code = "amFtQXBpOm5pNWY0eFRjRlpNc0lXNEd4IUR5cQ=="
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,7 +46,4 @@ JamAdmin::Application.configure do
|
|||
config.email_generic_from = 'nobody-dev@jamkazam.com'
|
||||
config.email_alerts_alias = 'alerts-dev@jamkazam.com'
|
||||
config.email_social_alias = 'social-dev@jamkazam.com'
|
||||
|
||||
config.latency_data_host = "http://localhost:4001/local"
|
||||
config.latency_data_host_auth_code = "c2VydmVyOnBhc3N3b3Jk"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
class JamRuby::JamTrackRight
|
||||
attr_accessible :jam_track, :user, :jam_track_id_val, :user_id_val, as: :admin
|
||||
|
||||
def jam_track_id_val
|
||||
|
||||
end
|
||||
|
||||
def jam_track_id_val=(val)
|
||||
end
|
||||
|
||||
def user_id_val
|
||||
|
||||
end
|
||||
|
||||
def user_id_val=(val)
|
||||
end
|
||||
end
|
||||
|
|
@ -3,8 +3,4 @@ class JamRuby::JamTrack
|
|||
# add a custom validation
|
||||
|
||||
|
||||
def autocomplete_display_name
|
||||
"#{original_artist} - #{name}"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,15 +14,6 @@ JamAdmin::Application.routes.draw do
|
|||
namespace :admin do
|
||||
resources :users do
|
||||
get :autocomplete_user_email, :on => :collection
|
||||
get :add_school_user, on: :collection
|
||||
post :add_school_user, on: :collection
|
||||
patch :add_school_user, on: :member
|
||||
post :user_latencies, on: :collection
|
||||
post :user_latency_recommendation, on: :collection
|
||||
end
|
||||
|
||||
resources :jam_tracks do
|
||||
get :autocomplete_jam_track_name, :on => :collection
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -44,8 +35,6 @@ JamAdmin::Application.routes.draw do
|
|||
match '/api/jam_tracks/released' => 'jam_track#dump_released', :via => :get, as: 'released_jamtracks_csv'
|
||||
|
||||
match '/api/arses/register' => 'arses#get_or_create', :via => :post
|
||||
match '/api/arses' => 'arses#index', :via => :get
|
||||
match '/api/arses/:id' => 'arses#update', :via => :post
|
||||
|
||||
mount Resque::Server.new, :at => "/resque"
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
# trigger build
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
image: node:14.21.3
|
||||
|
||||
pipelines:
|
||||
branches:
|
||||
develop:
|
||||
- step:
|
||||
name: Build Staging
|
||||
script:
|
||||
- pushd jam-ui
|
||||
- npm install
|
||||
- popd
|
||||
- pushd jam-ui/cicd
|
||||
- npm install
|
||||
- NODE_ENV=production PUBLIC_URL=https://staging.jamkazam.com REACT_APP_ORIGIN=staging.jamkazam.com REACT_APP_BASE_URL=https://staging.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT ENVIRONMENT=staging ./generate.sh
|
||||
- popd
|
||||
- cd jam-ui
|
||||
- NODE_ENV=production CI=false PUBLIC_URL=https://staging.jamkazam.com REACT_APP_ORIGIN=staging.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com REACT_APP_BASE_URL=https://staging.jamkazam.com REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT npm run build
|
||||
artifacts:
|
||||
- jam-ui/build/**
|
||||
- step:
|
||||
name: Deploy to staging - SPA
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/stg"
|
||||
LOCAL_PATH: "jam-ui/build"
|
||||
EXTRA_ARGS: "--exclude=*backing-tracks/*"
|
||||
- step:
|
||||
name: Deploy to staging - backing-tracks
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/stg/backing-tracks"
|
||||
LOCAL_PATH: "jam-ui/build/backing-tracks"
|
||||
EXTRA_ARGS: "--exclude=*.js --content-type text/html"
|
||||
- step:
|
||||
name: Deploy to staging - backing-tracks js
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/stg/js"
|
||||
LOCAL_PATH: "jam-ui/build/js"
|
||||
EXTRA_ARGS: "--content-type text/javascript"
|
||||
# - step:
|
||||
# name: Deploy to staging - invalidate cloudfront distribution
|
||||
# deployment: staging
|
||||
# script:
|
||||
# - pipe: atlassian/aws-cloudfront-invalidate:0.10.1
|
||||
# variables:
|
||||
# DISTRIBUTION_ID: "E2AQIC9RSON94Q" # ESQDIABYLT0RV
|
||||
custom:
|
||||
build-and-deploy-to-production:
|
||||
- step:
|
||||
name: Build Production
|
||||
script:
|
||||
- pushd jam-ui
|
||||
- npm install
|
||||
- popd
|
||||
- pushd jam-ui/cicd
|
||||
- npm install
|
||||
- NODE_ENV=production ENVIRONMENT=production PUBLIC_URL=https://www.jamkazam.com REACT_APP_ORIGIN=jamkazam.com REACT_APP_BASE_URL=https://www.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com REACT_APP_API_BASE_URL=https://www.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB ./generate.sh
|
||||
- popd
|
||||
- cd jam-ui
|
||||
- NODE_ENV=production CI=false PUBLIC_URL=https://www.jamkazam.com REACT_APP_ORIGIN=jamkazam.com REACT_APP_BASE_URL=https://www.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com REACT_APP_API_BASE_URL=https://www.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB npm run build
|
||||
|
||||
artifacts:
|
||||
- jam-ui/build/**
|
||||
- step:
|
||||
name: Deploy to production - SPA
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/prd"
|
||||
LOCAL_PATH: "jam-ui/build"
|
||||
EXTRA_ARGS: "--exclude=*backing-tracks/*"
|
||||
- step:
|
||||
name: Deploy to production - backing-tracks
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/prd/backing-tracks"
|
||||
LOCAL_PATH: "jam-ui/build/backing-tracks"
|
||||
EXTRA_ARGS: "--exclude=*.js --content-type text/html"
|
||||
- step:
|
||||
name: Deploy to production - backing-tracks js
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/prd/js"
|
||||
LOCAL_PATH: "jam-ui/build/js"
|
||||
EXTRA_ARGS: "--content-type text/javascript"
|
||||
#- step:
|
||||
# name: Deploy to production - invalidate cloudfront distribution
|
||||
# deployment: production
|
||||
# script:
|
||||
# - pipe: atlassian/aws-cloudfront-invalidate:0.10.1
|
||||
# variables:
|
||||
# DISTRIBUTION_ID: "ESQDIABYLT0RV"
|
||||
1
build
1
build
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
# RUN_SLOW_TESTS, RUN_AWS_TESTS, SKIP_KARMA=1 SHOW_JS_ERRORS=1 PACKAGE=1
|
||||
# WORKSPACE=/var/lib/jenkins/jobs/jam-web/workspace
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
# Browsers that we support
|
||||
|
||||
last 1 version
|
||||
> 0.2%
|
||||
not op_mini all
|
||||
not dead
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
HOST=beta.jamkazam.local
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=jamkazam.local
|
||||
REACT_APP_BASE_URL=http://beta.jamkazam.local:4000
|
||||
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
|
||||
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
||||
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
||||
REACT_APP_BITBUCKET_COMMIT=dev
|
||||
REACT_APP_ENV=development
|
||||
REACT_APP_RECAPTCHA_ENABLED=false
|
||||
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-MC9BTWXWY4
|
||||
PUBLIC_URL=
|
||||
REACT_APP_COOKIE_DOMAIN=.jamkazam.local
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-hvDV1xQxDw0HPaaRFP4KNE
|
||||
REACT_APP_BRAINTREE_TOKEN=sandbox_pgjp8dvs_5v5rwm94m2vrfbms
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
HOST=beta.jamkazam.local
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=jamkazam.local
|
||||
REACT_APP_BASE_URL=http://beta.jamkazam.local:4000
|
||||
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
|
||||
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
||||
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
||||
REACT_APP_BITBUCKET_COMMIT=dev
|
||||
REACT_APP_ENV=development
|
||||
REACT_APP_COOKIE_DOMAIN=.jamkazam.com
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-MC9BTWXWY4
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=
|
||||
REACT_APP_BRAINTREE_TOKEN=
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
HOST=beta.jamkazam.com
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=jamkazam.com
|
||||
REACT_APP_BASE_URL=https://www.jamkazam.com
|
||||
REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com
|
||||
REACT_APP_API_BASE_URL=https://www.jamkazam.com/api
|
||||
REACT_APP_ENV=production
|
||||
REACT_APP_RECAPTCHA_ENABLED=true
|
||||
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
|
||||
REACT_APP_COOKIE_DOMAIN=.jamkazam.com
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-hvDV1xQxDw0HPaaRFP4KNE
|
||||
REACT_APP_BRAINTREE_TOKEN=production_hc7z69yq_pwwc6zm3d478kfrh
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
HOST=beta.staging.jamkazam.com
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=staging.jamkazam.com
|
||||
REACT_APP_BASE_URL=https://staging.jamkazam.com
|
||||
REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com
|
||||
REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api
|
||||
REACT_APP_ENV=staging
|
||||
REACT_APP_RECAPTCHA_ENABLED=false
|
||||
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
|
||||
REACT_APP_COOKIE_DOMAIN=.staging.jamkazam.com
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-AjUHUfcLtIsPdtetD4mj2x
|
||||
REACT_APP_BRAINTREE_TOKEN=sandbox_pgjp8dvs_5v5rwm94m2vrfbms
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"extends": ["react-app", "prettier", "plugin:react/recommended"],
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"react/no-unescaped-entities": 0
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
.cypress.env.json
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
/.idea
|
||||
/.vscode
|
||||
/test-results
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
|
||||
/public/backing-tracks
|
||||
/public/js
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# Using the node alpine image to build the React app
|
||||
image: node:alpine
|
||||
|
||||
# Announce the URL as per CRA docs
|
||||
# https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#advanced-configuration
|
||||
variables:
|
||||
PUBLIC_URL: /react-falcon
|
||||
# Cache node modules - speeds up future builds
|
||||
cache:
|
||||
paths:
|
||||
- node_modules
|
||||
|
||||
# Name the stages involved in the pipeline
|
||||
stages:
|
||||
- deploy
|
||||
|
||||
# Job name for gitlab to recognise this results in assets for Gitlab Pages
|
||||
# https://docs.gitlab.com/ee/user/project/pages/introduction.html#gitlab-pages-requirements
|
||||
pages:
|
||||
stage: deploy
|
||||
script:
|
||||
- npm install # Install all dependencies
|
||||
- npm run build --prod # Build for prod
|
||||
- mv public _public # CRA and gitlab pages both use the public folder. Only do this in a build pipeline.
|
||||
- mv build public # Move build files to public dir for Gitlab Pages
|
||||
- cp public/index.html public/404.html # Required for react router browser history, but helps with https://blog.pshrmn.com/how-single-page-applications-work/
|
||||
artifacts:
|
||||
paths:
|
||||
- public # The built files for Gitlab Pages to serve
|
||||
only:
|
||||
- master # Only run on master branch
|
||||
|
|
@ -1 +0,0 @@
|
|||
v14.21.3
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
2.7.18
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
# JamKazam new react frontend UI/UX
|
||||
|
||||
`jam-ui` is a react app created using `create-react-app` utility. to run the app on your development environment you need to `cd jam-ui` and run `npm run start`
|
||||
|
||||
The changes to the source files are auto-loaded but sometimes you might need to force close it by crtl+c and then start manually.
|
||||
|
||||
The application files goes under `src` and the react components are placed under `src/components` directory. We have a convention of naming the files using JK prefix in the filename. For example `JKMusicSessions`.
|
||||
|
||||
The routes are defined in `jam-ui/src/components/dashboard/JKDashboardMain.js`
|
||||
|
||||
|
||||
## Running react app
|
||||
|
||||
In production this React app is supposed to run on beta.jamkazam.com subdomain which is same origin domain to the production Rails app (www.jamkazam.com). This way we utilize same session based user authentication of Rails web app for authenticating users. (It looks for remember_token session cookie in headers and if it is not availale redirect the user to Rails web app sign in page)
|
||||
|
||||
The DOMAIN and PORT running this app is defined in env.production file. This file also has env variables for connecting with Rails app. (When setting up in development you can copy the content of env.development.example in to env.development.local and change them according to your host setup)
|
||||
|
||||
HOST=beta.jamkazam.local
|
||||
PORT=4000
|
||||
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
|
||||
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
||||
|
||||
## Subdomains setup (development)
|
||||
|
||||
You need 2 host records created for React and and Rails app. For example
|
||||
|
||||
127.0.0.1 www.jamkazam.local #for Rails app
|
||||
127.0.0.1 beta.jamkazam.local #for React app
|
||||
|
||||
## Installing npm dependencies
|
||||
cd jam-ui
|
||||
npm install
|
||||
|
||||
## Running the app
|
||||
|
||||
cd jam-ui
|
||||
npm run start
|
||||
|
||||
This will open it in a borwser window at http://beta.jamkazam.local:3000. Of course for it to work you also need Rails (web) app and websocket app (websocket-gateway) running.
|
||||
|
||||
## Working with JamTracks
|
||||
|
||||
if you have the latest from develop, you can go:
|
||||
```
|
||||
cd cicd
|
||||
npm install
|
||||
./export_personal_jamtracks.sh
|
||||
./generate.js
|
||||
open http://beta.jamkazam.local:4000/backing-tracks/ac-dc/back-in-black.html
|
||||
```
|
||||
|
||||
You can also do none of the above, and go straight to:
|
||||
http://beta.jamkazam.local:4000/public/backing-tracks/ac-dc/back-in-black
|
||||
|
||||
I tried to make it so the SPA has 'secret routes' to these pages, which is convenient for us dev & testing
|
||||
but also tried to make it convenient to run the cicd approach of actually generating separate pages for each landing page (which is what those 5 steps cover)
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
build
|
||||
output
|
||||
node_modules
|
||||
public
|
||||
jam_track_tracks_for_jam_ui*
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
22
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
||||
"ignore": [
|
||||
"../src/components/e-commerce/*.js"
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import 'react-app-polyfill/ie9';
|
||||
import 'react-app-polyfill/stable';
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import Main from "../src/Main.js"
|
||||
import TemplatePage from "../src/components/jamtracks/JKJamTracksLandingTemplatePage.js"
|
||||
import ArtistTemplatePage from "../src/components/jamtracks/JKJamTracksArtistLandingTemplatePage.js"
|
||||
import '../src/helpers/initFA';
|
||||
import '../src/i18n/config';
|
||||
|
||||
const rootElement = document.getElementById("root");
|
||||
|
||||
// Ensure props are passed correctly (or fetch from the server)
|
||||
|
||||
const props = window.jamtrack_data;
|
||||
|
||||
console.log('init', props, rootElement);
|
||||
|
||||
// Hydrate the server-rendered React component
|
||||
//ReactDOM.hydrate(React.createElement(TemplatePage, props), rootElement);
|
||||
|
||||
ReactDOM.render(
|
||||
<Main>
|
||||
{props.song ? <TemplatePage {...props} /> : <ArtistTemplatePage {...props} /> }
|
||||
</Main>, rootElement
|
||||
);
|
||||
|
||||
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# check if 1st argument spceified; if it is, then set that to SAVE_TO
|
||||
if [ -n "$1" ]; then
|
||||
SAVE_TO="$1"
|
||||
else
|
||||
SAVE_TO=/tmp
|
||||
fi
|
||||
|
||||
echo "Saving to $SAVE_TO"
|
||||
|
||||
psql jam -c "COPY( select id, original_artist, name , original_artist_slug, name_slug, plan_code, slug, allow_free, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug || '/' || name_slug) as \"URL\", (select name from jam_track_licensors l where l.id = licensor_id) as \"Licensor\", vendor_id as \"Vendor ID\" FROM jam_tracks) TO '$SAVE_TO/jam_tracks_for_jam_ui.$USER.csv' with CSV HEADER;"
|
||||
|
||||
//https://jamkazam-public.s3.amazonaws.com
|
||||
|
||||
# dump all artists
|
||||
psql jam -c "COPY( select original_artist, original_artist_slug, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug ) as \"URL\" FROM jam_tracks group by original_artist, original_artist_slug) TO '$SAVE_TO/jam_tracks_for_jam_ui_artists.$USER.csv' with CSV HEADER;"
|
||||
|
||||
psql jam -c "COPY( select id, part, instrument_id, (select description from instruments where id = instrument_id) as instrument_description, track_type, position, preview_mp3_url, preview_url as preview_ogg_url, preview_aac_url from jam_track_tracks) TO '$SAVE_TO/jam_track_tracks_for_jam_ui.$USER.csv' with CSV HEADER;"
|
||||
|
||||
echo "Moving personal files to jamtracks-for-env"
|
||||
mkdir -p jamtracks-for-env
|
||||
sudo mv $SAVE_TO/jam_tracks_for_jam_ui.$USER.csv jamtracks-for-env
|
||||
sudo mv $SAVE_TO/jam_tracks_for_jam_ui_artists.$USER.csv jamtracks-for-env
|
||||
sudo mv $SAVE_TO/jam_track_tracks_for_jam_ui.$USER.csv jamtracks-for-env
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Ensure the correct number of arguments
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Usage: $0 <save_to_path> <server_env>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SAVE_TO="$1"
|
||||
server_env="$2"
|
||||
|
||||
# Validate server_env
|
||||
if [ "$server_env" != "staging" ] && [ "$server_env" != "production" ]; then
|
||||
echo "Error: server_env must be either 'staging' or 'production'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine SSH target
|
||||
if [ "$server_env" == "staging" ]; then
|
||||
SSH_TARGET="jam@int.jamkazam.com"
|
||||
else
|
||||
SSH_TARGET="jam@db.jamkazam.com"
|
||||
fi
|
||||
|
||||
echo "Saving to $SAVE_TO on $server_env"
|
||||
|
||||
# Run psql commands remotely
|
||||
ssh $SSH_TARGET "psql jam -c \"COPY( select id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, allow_free, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug || '/' || name_slug) as \"URL\", (select name from jam_track_licensors l where l.id = licensor_id) as \"Licensor\" FROM jam_tracks order by id::int) TO '$SAVE_TO/jam_tracks_for_jam_ui.$server_env.csv' with CSV HEADER;\""
|
||||
|
||||
ssh $SSH_TARGET "psql jam -c \"COPY( select original_artist, original_artist_slug, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug ) as \"URL\" FROM jam_tracks group by original_artist, original_artist_slug order by original_artist) TO '$SAVE_TO/jam_tracks_for_jam_ui_artists.$server_env.csv' with CSV HEADER;\""
|
||||
|
||||
ssh $SSH_TARGET "psql jam -c \"COPY( select id, part, instrument_id, (select description from instruments where id = instrument_id) as instrument_description, track_type, position, preview_mp3_url, preview_url as preview_ogg_url, preview_aac_url from jam_track_tracks order by jam_track_id::int) TO '$SAVE_TO/jam_track_tracks_for_jam_ui.$server_env.csv' with CSV HEADER;\""
|
||||
|
||||
# Move files locally from the remote server
|
||||
scp $SSH_TARGET:"$SAVE_TO/jam_tracks_for_jam_ui.$server_env.csv" jamtracks-for-env
|
||||
scp $SSH_TARGET:"$SAVE_TO/jam_tracks_for_jam_ui_artists.$server_env.csv" jamtracks-for-env
|
||||
scp $SSH_TARGET:"$SAVE_TO/jam_track_tracks_for_jam_ui.$server_env.csv" jamtracks-for-env
|
||||
|
||||
echo "Files moved successfully to local machine"
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const csv = require("csv-parser");
|
||||
const React = require("react");
|
||||
const dotenv = require("dotenv");
|
||||
const ReactDOMServer = require("react-dom/server");
|
||||
const TemplatePageModule = require("./build/components/jamtracks/JKJamTracksLandingTemplatePage");
|
||||
const ArtistTemplatePageModule = require("./build/components/jamtracks/JKJamTracksArtistLandingTemplatePage");
|
||||
|
||||
var csvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui.${process.env.USER}.csv`
|
||||
var artistCsvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui_artists.${process.env.USER}.csv`
|
||||
|
||||
var sitemapPath = path.join(__dirname, "..", "public", "sitemap.xml");
|
||||
const clear_sitemap = () => {
|
||||
fs.writeFileSync(sitemapPath, "");
|
||||
|
||||
// Add the root element
|
||||
fs.writeFileSync(sitemapPath, `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`, { flag: 'a' });
|
||||
|
||||
// Add the root url
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}</loc></url>\n`, { flag: 'a' });
|
||||
|
||||
// Add standard URLs specific to this site, such as:
|
||||
// All prefix with /public
|
||||
|
||||
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/</loc></url>\n`, { flag: 'a' });
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/privacy</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/help</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/knowledge-base</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/help-desk</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/forum</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/unsubscribe</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/downloads</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/downloads-legacy</loc></url>\n`, { flag: 'a' } );
|
||||
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/auth/login</loc></url>\n`, { flag: 'a' });
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/auth/signup</loc></url>\n`, { flag: 'a' } );
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/auth/forget-password</loc></url>\n`, { flag: 'a' } );
|
||||
|
||||
// Add the closing root element
|
||||
}
|
||||
|
||||
const add_song_to_sitemap = (artistSlug, songSlug) => {
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/backing-tracks/${artistSlug}/${songSlug}</loc></url>\n`, { flag: 'a' });
|
||||
}
|
||||
|
||||
const add_artist_to_sitemap = (artistSlug) => {
|
||||
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/backing-tracks/${artistSlug}</loc></url>\n`, { flag: 'a' });
|
||||
}
|
||||
|
||||
const close_sitemap = () => {
|
||||
fs.writeFileSync(sitemapPath, "</urlset>", { flag: 'a' } );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a CSV file into an array of objects.
|
||||
* @param {string} csvPath - The path to the CSV file.
|
||||
* @returns {Promise<Array<Object>>} - A promise that resolves with the parsed CSV data.
|
||||
*/
|
||||
const load_csv = (csvPath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const results = [];
|
||||
fs.createReadStream(csvPath)
|
||||
.pipe(csv())
|
||||
.on('data', (data) => results.push(data))
|
||||
.on('end', () => resolve(results))
|
||||
.on('error', (error) => reject(error));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds all songs for a given artist based on the original_artist_slug
|
||||
* and sorts them alphabetically by the `slug` field.
|
||||
* @param {string} artistSlug - The original_artist_slug to match.
|
||||
* @param {Array<Object>} songsCsv - The songs CSV data.
|
||||
* @returns {Array<Object>} - A sorted array of matching song objects.
|
||||
*/
|
||||
const collect_songs_for_artist = (artistSlug, songsCsv) => {
|
||||
return songsCsv
|
||||
.filter((song) => song.original_artist_slug === artistSlug)
|
||||
.sort((a, b) => a.slug.localeCompare(b.slug)); // Sort alphabetically by slug
|
||||
};
|
||||
|
||||
|
||||
const init = () => {
|
||||
const node_env = process.env.NODE_ENV || 'development';
|
||||
const environment = process.env.ENVIRONMENT || 'development';
|
||||
console.log(`environment=${environment} node_env=${node_env}`);
|
||||
console.log(dotenv.config({ path: `../.env.${environment}` }));
|
||||
|
||||
if (environment === "production" || environment === "staging") {
|
||||
csvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui.${environment}.csv`;
|
||||
artistCsvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui_artists.${environment}.csv`;
|
||||
}
|
||||
|
||||
console.log("Song csv file", csvFilePath);
|
||||
console.log("Artist csv file", artistCsvFilePath);
|
||||
|
||||
if (!process.env.PUBLIC_URL) {
|
||||
console.log("setting public url", process.env.REACT_APP_BASE_URL);
|
||||
process.env.PUBLIC_URL = process.env.REACT_APP_BASE_URL;
|
||||
}
|
||||
|
||||
clear_sitemap();
|
||||
|
||||
|
||||
//const __dirname = path.resolve(path.dirname(''));
|
||||
|
||||
console.log("init done successfully")
|
||||
}
|
||||
|
||||
const generateSongPages = async (render) => {
|
||||
const rows = [];
|
||||
|
||||
const OUTPUT_DIR = path.join(__dirname, "..", "public", "backing-tracks");
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
console.log("generatPages starting")
|
||||
|
||||
|
||||
const TemplatePage = TemplatePageModule.default;
|
||||
|
||||
fs.createReadStream(csvFilePath)
|
||||
.pipe(csv())
|
||||
.on("data", (row) => rows.push(row))
|
||||
.on("end", async () => {
|
||||
console.log(`Processing ${rows.length} rows...`);
|
||||
|
||||
for (const row of rows) {
|
||||
// id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, URL, licensor, vendor_id
|
||||
const { id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, allow_free } = row;
|
||||
const artist = original_artist;
|
||||
const song = name;
|
||||
const location = `/backing-tracks/${original_artist_slug}/${name_slug}`;
|
||||
const fullPath = process.env.REACT_APP_BASE_URL + location;
|
||||
const logoPath = process.env.REACT_APP_BASE_URL + "/favicon.svg";
|
||||
|
||||
add_song_to_sitemap(original_artist_slug, name_slug);
|
||||
|
||||
console.log(`Generating ${artist} - ${song}`);
|
||||
|
||||
const html = render
|
||||
? ReactDOMServer.renderToStaticMarkup(
|
||||
React.createElement(TemplatePage, { id, plan_code, slug, artist, song, location })
|
||||
)
|
||||
: "";
|
||||
const fullHtml = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="shortcut icon" href="/favicon.svg">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${artist} - ${song} - Free Backing Track</title>
|
||||
<link rel="stylesheet" href="${process.env.REACT_APP_BASE_URL}/css/theme.css">
|
||||
<meta name="description" content="Get free ${song} by ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta name="keywords" content="Backing Track, ${artist}, ${song}, Instrumental">
|
||||
<meta name="author" content="JamKazam">
|
||||
|
||||
<!-- Open Graph (Facebook, LinkedIn, etc.) -->
|
||||
<meta property="og:title" content="${artist} - ${song} | Free Backing Track">
|
||||
<meta property="og:description" content="Get free ${song} by ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta property="og:image" content="${logoPath}">
|
||||
<meta property="og:url" content="${fullPath}">
|
||||
<meta property="og:type" content="music.song">
|
||||
|
||||
<!-- Twitter Cards -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="${artist} - ${song} | Free Backing Track">
|
||||
<meta name="twitter:description" content="Get free ${song} by ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta name="twitter:image" content="${logoPath}">
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="${fullPath}" />
|
||||
|
||||
<!-- Structured Data (Schema.org) -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "MusicRecording",
|
||||
"name": "${song}",
|
||||
"byArtist": {
|
||||
"@type": "MusicGroup",
|
||||
"name": "${artist}"
|
||||
},
|
||||
"url": "${fullPath}",
|
||||
"image": "${logoPath}"
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
window.jamtrack_data = {
|
||||
id: "${id}",
|
||||
plan_code: "${plan_code}",
|
||||
slug: "${slug}",
|
||||
artist: "${artist}",
|
||||
song: "${song}",
|
||||
location: "${location}"
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
<script src="/js/client-hydrate.bundle.js"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const ARTIST_DIR = path.join(OUTPUT_DIR, original_artist_slug);
|
||||
|
||||
if (!fs.existsSync(ARTIST_DIR)) {
|
||||
fs.mkdirSync(ARTIST_DIR, { recursive: false });
|
||||
}
|
||||
|
||||
const finalOutputPath = process.env.NODE_ENV === "development" ? `${name_slug}.html` : `${name_slug}.html`;
|
||||
const outputFilePath = path.join(ARTIST_DIR, finalOutputPath);
|
||||
fs.writeFileSync(outputFilePath, fullHtml);
|
||||
console.log(`Generated: ${outputFilePath}`);
|
||||
}
|
||||
|
||||
console.log("All pages generated!");
|
||||
});
|
||||
};
|
||||
|
||||
const generateArtistPages = async (render) => {
|
||||
const rows = [];
|
||||
|
||||
const OUTPUT_DIR = path.join(__dirname, "..", "public", "backing-tracks");
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
console.log("generatPages starting")
|
||||
|
||||
|
||||
const TemplatePage = TemplatePageModule.default;
|
||||
|
||||
const songs_csv = await load_csv(csvFilePath);
|
||||
|
||||
fs.createReadStream(artistCsvFilePath)
|
||||
.pipe(csv())
|
||||
.on("data", (row) => rows.push(row))
|
||||
.on("end", async () => {
|
||||
console.log(`Processing ${rows.length} rows...`);
|
||||
|
||||
for (const row of rows) {
|
||||
const { original_artist, original_artist_slug, url } = row;
|
||||
const artist = original_artist;
|
||||
|
||||
const matchingSongs = collect_songs_for_artist(original_artist_slug, songs_csv);
|
||||
console.log(`Found ${matchingSongs.length} songs for ${artist}`);
|
||||
|
||||
const location = `/backing-tracks/${original_artist_slug}`;
|
||||
const fullPath = process.env.REACT_APP_BASE_URL + location;
|
||||
const logoPath = process.env.REACT_APP_BASE_URL + "/favicon.svg";
|
||||
|
||||
add_artist_to_sitemap(original_artist_slug);
|
||||
console.log(`Generating ${artist}`);
|
||||
|
||||
const songs = matchingSongs.map((song) => {
|
||||
return {
|
||||
name: song.name,
|
||||
plan_code: song.plan_code,
|
||||
url: process.env.REACT_APP_BASE_URL + "/backing-tracks/" + song.original_artist_slug + "/" + song.name_slug
|
||||
}
|
||||
});
|
||||
const html = render
|
||||
? ReactDOMServer.renderToStaticMarkup(
|
||||
React.createElement(ArtistTemplatePage, { artist, original_artist_slug, location })
|
||||
)
|
||||
: "";
|
||||
const fullHtml = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="shortcut icon" href="/favicon.svg">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${artist} - Free Backing Track</title>
|
||||
<link rel="stylesheet" href="${process.env.REACT_APP_BASE_URL}/css/theme.css">
|
||||
<meta name="description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta name="keywords" content="Backing Track, ${artist}, Instrumental">
|
||||
<meta name="author" content="JamKazam">
|
||||
|
||||
<!-- Open Graph (Facebook, LinkedIn, etc.) -->
|
||||
<meta property="og:title" content="${artist} | Free Backing Track">
|
||||
<meta property="og:description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta property="og:image" content="${logoPath}">
|
||||
<meta property="og:url" content="${fullPath}">
|
||||
<meta property="og:type" content="music.song">
|
||||
|
||||
<!-- Twitter Cards -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="${artist} | Free Backing Track">
|
||||
<meta name="twitter:description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta name="twitter:image" content="${logoPath}">
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="${fullPath}" />
|
||||
|
||||
<script>
|
||||
window.jamtrack_data = {
|
||||
artist: "${artist}",
|
||||
original_artist_slug: "${original_artist_slug}",
|
||||
location: "${location}",
|
||||
songs: ${JSON.stringify(songs)}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
<script src="/js/client-hydrate.bundle.js"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const finalOutputPath = process.env.NODE_ENV === "development" ? `${original_artist_slug}.html` : `${original_artist_slug}.html`;
|
||||
const outputFilePath = path.join(OUTPUT_DIR, finalOutputPath);
|
||||
fs.writeFileSync(outputFilePath, fullHtml);
|
||||
console.log(`Generated: ${outputFilePath}`);
|
||||
}
|
||||
|
||||
close_sitemap();
|
||||
|
||||
console.log("All pages generated!");
|
||||
});
|
||||
};
|
||||
|
||||
let render = false;
|
||||
if (process.argv.length > 2) {
|
||||
render = process.argv[2] === "true" || process.argv[2] === "yes" || process.argv[2] === "1";
|
||||
}
|
||||
|
||||
init()
|
||||
generateSongPages(render);
|
||||
|
||||
generateArtistPages(render);
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# requires node 22 at least
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
# default NODE_ENV to development if not set
|
||||
if [ -z "$NODE_ENV" ]; then
|
||||
NODE_ENV=development
|
||||
fi
|
||||
|
||||
# default ENVIRONMENT to development if not set
|
||||
if [ -z "$ENVIRONMENT" ]; then
|
||||
ENVIRONMENT=development
|
||||
fi
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
export NODE_ENV
|
||||
export ENVIRONMENT
|
||||
|
||||
echo "cleaning"
|
||||
rm -rf $SCRIPT_DIR/build
|
||||
|
||||
echo "creating build dir - this is for correct image resolution; ideally this wouldn't be needed"
|
||||
|
||||
#mkdir -p $SCRIPT_DIR/build/assets/img
|
||||
#cp -r $SCRIPT_DIR/../src/assets/img/* $SCRIPT_DIR/build/assets/img/
|
||||
|
||||
echo "creating client-hydrate.bundle.js for jamtrack landing pages"
|
||||
# PUBLIC_URL=? for server builds
|
||||
# NODE_ENV=production for server builds
|
||||
npx webpack
|
||||
#cp -r public/* output/
|
||||
|
||||
|
||||
npm run build
|
||||
|
||||
echo "run generate.js for all jamtracks defined in the CSV"
|
||||
NODE_ENV=$NODE_ENV ENVIRONMENT=$ENVIRONMENT npm run generate-song-landing-pages
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"name": "react-static-site-generator",
|
||||
"version": "1.0.0",
|
||||
"description": "A React-based static site generator from CSV",
|
||||
"main": "generate.js",
|
||||
"dependencies": {
|
||||
"csv-parser": "^3.0.0",
|
||||
"react": "^16.4.1",
|
||||
"react-dom": "^16.4.1"
|
||||
},
|
||||
"scripts": {
|
||||
"generate-song-landing-pages": "node generate.js",
|
||||
"build": "babel ../src/ --out-dir build/",
|
||||
"webpack": "webpack"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.26.4",
|
||||
"@babel/core": "^7.26.9",
|
||||
"@babel/preset-env": "^7.26.9",
|
||||
"@babel/preset-react": "^7.26.3",
|
||||
"@babel/register": "^7.25.9",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"babel-loader": "^9.2.1",
|
||||
"dotenv-webpack": "^8.1.0",
|
||||
"image-minimizer-webpack-plugin": "^4.1.3",
|
||||
"imagemin": "^9.0.0",
|
||||
"webpack": "^5.98.0",
|
||||
"webpack-cli": "^6.0.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
const path = require("path");
|
||||
const webpack = require('webpack');
|
||||
const Dotenv = require("dotenv-webpack");
|
||||
|
||||
const environment = process.env.ENVIRONMENT || 'development';
|
||||
const node_env = process.env.NODE_ENV || 'development';
|
||||
const debug = node_env == 'development';
|
||||
module.exports = {
|
||||
entry: "./client-hydrate.js",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "..", "public", "js"),
|
||||
filename: "client-hydrate.bundle.js",
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react'
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg/,
|
||||
type: 'asset/inline'
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)$/i,
|
||||
type: 'asset',
|
||||
}
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".js", ".jsx"],
|
||||
alias: {
|
||||
react: path.resolve('./node_modules/react'),
|
||||
}
|
||||
},
|
||||
devtool: debug ? 'eval-source-map' : 'source-map',
|
||||
mode: node_env,
|
||||
plugins: [
|
||||
new Dotenv({
|
||||
path: `../.env.${environment}`
|
||||
})
|
||||
],
|
||||
optimization: {
|
||||
minimize: node_env === 'production', //only minimize in production
|
||||
},
|
||||
};
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
legacyBaseUrl: "http://www.jamkazam.local:3000",
|
||||
apiBaseUrl: "http://www.jamkazam.local:3000/api",
|
||||
},
|
||||
|
||||
e2e: {
|
||||
// We've imported your old cypress plugins here.
|
||||
// You may want to clean this up later by importing these.
|
||||
setupNodeEvents(on, config) {
|
||||
return require("./cypress/plugins/index.js")(on, config);
|
||||
},
|
||||
baseUrl: "http://beta.jamkazam.local:4000",
|
||||
},
|
||||
|
||||
component: {
|
||||
devServer: {
|
||||
framework: "react",
|
||||
bundler: "webpack",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"baseUrl": "http://beta.jamkazam.local:4000",
|
||||
"legacyBaseUrl": "http://www.jamkazam.local:3000",
|
||||
"apiBaseUrl": "http://www.jamkazam.local:3000/api"
|
||||
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('Change Current Email/Password Feature', () => {
|
||||
beforeEach(() => {
|
||||
// Log in to the application or navigate to the account page
|
||||
// where the change email feature is available
|
||||
const currentUser = makeFakeUser({
|
||||
email: 'sam@example.com'
|
||||
});
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.visit('/account/identity');
|
||||
});
|
||||
|
||||
describe('Email update', () => {
|
||||
it('should display the current email address', () => {
|
||||
// Assert that the current email address is displayed
|
||||
cy.get('[data-testid=edit_email_form]').within($form => {
|
||||
cy.get('input#new_email[placeholder="sam@example.com"]');
|
||||
});
|
||||
});
|
||||
|
||||
it('shows validation error if no data is entered', () => {
|
||||
// Assert that an error message is displayed
|
||||
cy.get('[data-testid=edit_email_form]').within($form => {
|
||||
cy.get('[data-testid=email_submit]').click();
|
||||
cy.contains('Current password is required');
|
||||
cy.contains('New Email is required');
|
||||
});
|
||||
});
|
||||
|
||||
it('shows validation error if new email is invalid', () => {
|
||||
cy.get('[data-testid=edit_email_form]').within($form => {
|
||||
// Enter the current password
|
||||
cy.get('input#current_password').type('password');
|
||||
// Enter an invalid email address in the input field
|
||||
cy.get('input#new_email').type('invalidemail');
|
||||
|
||||
cy.get('[data-testid=email_submit]').click();
|
||||
// Assert that an error message is displayed
|
||||
cy.contains('Email is invalid');
|
||||
});
|
||||
});
|
||||
|
||||
it('reveal password', () => {
|
||||
cy.get('[data-testid=edit_email_form]').within($form => {
|
||||
// Click on the reveal password button
|
||||
cy.get('.input-group-append').click();
|
||||
// Assert that the password is revealed
|
||||
cy.get('input#current_password').should('have.attr', 'type', 'text');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the user submits the form', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', /\S+\/users\S+/, {
|
||||
statusCode: 200
|
||||
}).as('updateEmail');
|
||||
});
|
||||
|
||||
it('should update the email address', () => {
|
||||
cy.get('[data-testid=edit_email_form]').within($form => {
|
||||
// Enter the current password
|
||||
cy.get('input#current_password').type('password');
|
||||
// Enter the new email address
|
||||
cy.get('input#new_email').type('samsam@example.com');
|
||||
|
||||
// Submit the form
|
||||
cy.get('[data-testid=email_submit]').click();
|
||||
});
|
||||
|
||||
// Assert that the email address is updated
|
||||
cy.contains('A confirmation email has been sent to your email address');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Password update', () => {
|
||||
it('shows validation error if no data is entered', () => {
|
||||
// Assert that an error message is displayed
|
||||
cy.get('[data-testid=edit_password_form]').within($form => {
|
||||
cy.get('[data-testid=password_submit]').click();
|
||||
cy.contains('Current password is required');
|
||||
cy.contains('New password is required');
|
||||
});
|
||||
});
|
||||
|
||||
it('reveal password', () => {
|
||||
cy.get('[data-testid=edit_password_form]').within($form => {
|
||||
// Click on the reveal password button
|
||||
cy.get('.current-password-reveal').click();
|
||||
// Assert that the password is revealed
|
||||
cy.get('input#current_password').should('have.attr', 'type', 'text');
|
||||
|
||||
// Click on the reveal password button
|
||||
cy.get('.new-password-reveal').click();
|
||||
// Assert that the password is revealed
|
||||
cy.get('input#new_password').should('have.attr', 'type', 'text');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Submit form with errors', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', /\S+\/users\S+\/set_password/, {
|
||||
statusCode: 422,
|
||||
body: {
|
||||
errors: {
|
||||
password: ['is too short']
|
||||
}
|
||||
}
|
||||
}).as('updatePassword');
|
||||
});
|
||||
|
||||
it('shows validation error if new password is invalid', () => {
|
||||
cy.get('[data-testid=edit_password_form]').within($form => {
|
||||
// Enter the current password
|
||||
cy.get('input#current_password').type('password');
|
||||
// Enter an invalid new password
|
||||
cy.get('input#new_password').type('short');
|
||||
|
||||
cy.get('[data-testid=password_submit]').click();
|
||||
// Assert that an error message is displayed
|
||||
cy.contains('New Password is too short');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Submit with valid data', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', /\S+\/users\S+\/set_password/, {
|
||||
statusCode: 200
|
||||
}).as('updatePassword');
|
||||
});
|
||||
|
||||
it('should update the password', () => {
|
||||
cy.get('[data-testid=edit_password_form]').within($form => {
|
||||
// Enter the current password
|
||||
cy.get('input#current_password').type('password');
|
||||
// Enter the new password
|
||||
cy.get('input#new_password').type('newpassword');
|
||||
|
||||
// Submit the form
|
||||
cy.get('[data-testid=password_submit]').click();
|
||||
});
|
||||
|
||||
// Assert that the password is updated
|
||||
cy.contains('password has been successfully updated');
|
||||
});
|
||||
})
|
||||
|
||||
describe('Forgot password', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', /\S+\/users\S+\/request_reset_password/, {
|
||||
statusCode: 200
|
||||
}).as('forgotPassword');
|
||||
});
|
||||
|
||||
it('sends forgot password email', () => {
|
||||
cy.get('[data-testid=forgot_password]').click();
|
||||
cy.contains('A password reset email has been sent to your email');
|
||||
});
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('Account Preferences Feature', () => {
|
||||
beforeEach(() => {
|
||||
// Log in to the application or navigate to the account page
|
||||
// where the change email feature is available
|
||||
const currentUser = makeFakeUser({
|
||||
email: 'sam@example.com',
|
||||
recording_pref: 0
|
||||
});
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.intercept('POST', /\S+\/users\S+/, {
|
||||
statusCode: 200
|
||||
}).as('updateUser');
|
||||
cy.visit('/account/preferences');
|
||||
});
|
||||
|
||||
it('should display the current recording preference', () => {
|
||||
// Assert that the current recording preference is displayed
|
||||
cy.get('[data-testid=recording_pref_none]').should('be.checked');
|
||||
});
|
||||
|
||||
it('should save the new recording preference', () => {
|
||||
// Select a new recording preference
|
||||
cy.get('[data-testid=recording_pref_my_audio]').check('1');
|
||||
cy.wait('@updateUser');
|
||||
// Assert that the new recording preference is saved
|
||||
cy.contains('Recording preference saved successfully.');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('User subscribe to a plan', () => {
|
||||
beforeEach(() => {
|
||||
// Log in to the application or navigate to the account page
|
||||
// where the change email feature is available
|
||||
const currentUser = makeFakeUser({
|
||||
email: 'sam@example.com'
|
||||
});
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.stubGonSubscriptionCodes();
|
||||
|
||||
|
||||
cy.intercept('GET', /\S+\/get_subscription/, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
past_due: false,
|
||||
has_billing_info: true,
|
||||
plan_code: 'jamsubsilver',
|
||||
desired_plan_code: 'jamsubgold',
|
||||
admin_overide_plan_code: null,
|
||||
admin_overide_ends_at: null,
|
||||
in_trial: false,
|
||||
trial_ends_at: null,
|
||||
subscription: {
|
||||
|
||||
},
|
||||
subscription_rules: {
|
||||
remaining_monthly_play_time: null
|
||||
}
|
||||
}
|
||||
}).as('getSubscription');
|
||||
|
||||
cy.intercept('GET', /\S+\/get_subscription/, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
past_due: false,
|
||||
has_billing_info: true,
|
||||
plan_code: '',
|
||||
desired_plan_code: '',
|
||||
admin_overide_plan_code: null,
|
||||
admin_overide_ends_at: null,
|
||||
in_trial: false,
|
||||
trial_ends_at: null,
|
||||
subscription: {
|
||||
|
||||
},
|
||||
subscription_rules: {
|
||||
remaining_monthly_play_time: null
|
||||
}
|
||||
}
|
||||
}).as('getSubscriptionWithNoPlan');
|
||||
|
||||
});
|
||||
|
||||
it('should display the current plan', () => {
|
||||
cy.visit('/account/subscription');
|
||||
cy.wait('@getSubscription')
|
||||
// Assert that the current plan is displayed
|
||||
cy.get('[data-testid=changeSubscriptionForm]').within($form => {
|
||||
cy.get('label').contains('Subscription Plan');
|
||||
cy.get('.select-plan__single-value').should('contain', 'Gold ($9.99/month)');
|
||||
cy.get('input[type=submit]').should('have.value', 'Save Plan').should('be.disabled');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=playtime]').within($playtime => {
|
||||
cy.get('label').contains('You have unlimited play time');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=subscription-explanation]').within($expl => {
|
||||
cy.get('.alert').contains('You are currently on the Silver (monthly) level, thank you!');
|
||||
});
|
||||
});
|
||||
|
||||
it.only('should display the current plan when no plan', () => {
|
||||
cy.visit('/account/subscription');
|
||||
cy.wait('@getSubscriptionWithNoPlan')
|
||||
// Assert that the current plan is displayed
|
||||
cy.get('[data-testid=changeSubscriptionForm]').within($form => {
|
||||
cy.get('label').contains('Subscription Plan');
|
||||
cy.get('.select-plan__single-value').should('contain', 'Free ($0.00/month)');
|
||||
cy.get('input[type=submit]').should('have.value', 'Save Plan').should('be.disabled');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=playtime]').within($playtime => {
|
||||
cy.get('label').contains('You have unlimited play time.');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=subscription-explanation]').within($expl => {
|
||||
cy.get('.alert').contains('You are currently on the Free (monthly) plan.');
|
||||
});
|
||||
});
|
||||
|
||||
it('change plan', () => {
|
||||
cy.visit('/account/subscription');
|
||||
cy.wait('@getSubscription')
|
||||
cy.get('[data-testid=changeSubscriptionForm]').within($form => {
|
||||
cy.get('.select-plan__control').click();
|
||||
cy.get('.select-plan__option').contains('Platinum ($19.99/month)').click();
|
||||
cy.get('input[type=submit]').should('be.enabled').click();
|
||||
});
|
||||
|
||||
const text = 'You have selected the PLATINUM MONTHLY PLAN and will be charged US$19.99'
|
||||
cy.contains('.modal-body', text).should('be.visible');
|
||||
cy.get('.modal-content').find('.modal-footer').contains('OK').click();
|
||||
|
||||
cy.get('.modal-body').should('not.be.visible');
|
||||
// cy.get('[data-testid=subscription-explanation]').within($expl => {
|
||||
// cy.get('.alert').contains('You are currently on the Silver (monthly) level, thank you! And your plan and billing will switch to the Platinum (monthly) level on the next billing cycle.');
|
||||
// });
|
||||
cy.get('input[type=submit]').should('be.disabled')
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
import makeFakeUser from '../../factories/user';
|
||||
describe('Change Email Confirm Page', () => {
|
||||
beforeEach(() => {
|
||||
// Log in to the application or navigate to the account page
|
||||
// where the change email feature is available
|
||||
const currentUser = makeFakeUser({
|
||||
email: 'sam@example.com'
|
||||
});
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.intercept('POST', /\S+\/update_email/, { statusCode: 200, body: { ok: true } });
|
||||
});
|
||||
|
||||
it('should display the confirm page when visiting the confirm URL', () => {
|
||||
// Replace with a realistic token for your app if needed
|
||||
const token = 'dummy-confirm-token';
|
||||
|
||||
// Visit the confirm URL
|
||||
cy.visit(`/confirm-email-change?token=${token}`);
|
||||
|
||||
// Assert that the JKChangeEmailConfirm page is rendered
|
||||
// Adjust selectors/texts as per your actual component
|
||||
cy.contains('Change Email Confirmation').should('be.visible');
|
||||
cy.contains('Loading...').should('be.visible');
|
||||
// Optionally, check for the success message after the email update
|
||||
cy.wait(1000); // Wait for the email update to complete
|
||||
cy.contains('Your email has been successfully updated.').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('Profile update', () => {
|
||||
beforeEach(() => {
|
||||
// Log in to the application or navigate to the account page
|
||||
// where the change email feature is available
|
||||
const currentUser = makeFakeUser();
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.intercept('GET', /\S+\/users\/\S+\/profile/, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
first_name: 'David',
|
||||
last_name: 'Wilson',
|
||||
name: 'David Wilson',
|
||||
city: 'Barstow',
|
||||
state: 'CA',
|
||||
country: 'US',
|
||||
location: 'Barstow, CA',
|
||||
photo_url: null,
|
||||
biography: 'This is the musician biography. It is a long form text.',
|
||||
virtual_band: true,
|
||||
virtual_band_commitment: 2,
|
||||
traditional_band: false,
|
||||
traditional_band_commitment: null,
|
||||
traditional_band_touring: false,
|
||||
paid_sessions: true,
|
||||
paid_sessions_hourly_rate: 19900,
|
||||
paid_sessions_daily_rate: 200000,
|
||||
free_sessions: true,
|
||||
cowriting: true,
|
||||
cowriting_purpose: 2,
|
||||
subscribe_email: true,
|
||||
genres: [
|
||||
{
|
||||
genre_id: 'asian',
|
||||
player_type: 'JamRuby::User',
|
||||
genre_type: 'profile'
|
||||
},
|
||||
{
|
||||
genre_id: 'blues',
|
||||
player_type: 'JamRuby::User',
|
||||
genre_type: 'profile'
|
||||
},
|
||||
{
|
||||
genre_id: 'dance',
|
||||
player_type: 'JamRuby::User',
|
||||
genre_type: 'profile'
|
||||
}
|
||||
],
|
||||
instruments: [
|
||||
{
|
||||
description: 'Acoustic Guitar',
|
||||
proficiency_level: 3,
|
||||
priority: 0,
|
||||
instrument_id: 'acoustic guitar'
|
||||
},
|
||||
{
|
||||
description: 'Bass Guitar',
|
||||
proficiency_level: 3,
|
||||
priority: 2,
|
||||
instrument_id: 'bass guitar'
|
||||
},
|
||||
{
|
||||
description: 'Violin',
|
||||
proficiency_level: 1,
|
||||
priority: 0,
|
||||
instrument_id: 'violin'
|
||||
},
|
||||
{
|
||||
description: 'Banjo',
|
||||
proficiency_level: 1,
|
||||
priority: 1,
|
||||
instrument_id: 'banjo'
|
||||
}
|
||||
]
|
||||
}
|
||||
}).as('getProfile');
|
||||
|
||||
cy.intercept('PUT', /\S+\/users\/\S+/, {
|
||||
statusCode: 200
|
||||
}).as('updateProfile');
|
||||
|
||||
cy.visit('/profile');
|
||||
});
|
||||
|
||||
it('should render the profile form with persisted data', () => {
|
||||
// Assert that the profile form is rendered
|
||||
cy.wait('@getProfile');
|
||||
cy.get('[data-testid=edit_profile_form]').within($form => {
|
||||
cy.get('[data-testid=firstName]').should('have.value', 'David');
|
||||
cy.get('[data-testid=lastName]').should('have.value', 'Wilson');
|
||||
cy.get('[data-testid=biography]').should('contain', 'This is the musician biography. It is a long form text');
|
||||
|
||||
cy.get('[data-testid=subscribeEmail]').should('be.checked');
|
||||
cy.get('[data-testid=virtualBand]').should('be.checked');
|
||||
cy.get('[data-testid=traditionalBand]').should('not.be.checked');
|
||||
cy.get('[data-testid=cowriting]').should('be.checked');
|
||||
cy.get('[data-testid=instruments] input:checked').should('have.length', 4);
|
||||
cy.get('[data-testid=genres] input:checked').should('have.length', 3);
|
||||
});
|
||||
});
|
||||
|
||||
it.only('should update the profile', () => {
|
||||
// Update the profile form
|
||||
|
||||
cy.get('[data-testid=edit_profile_form]').within($form => {
|
||||
// Update the first name
|
||||
cy.get('[data-testid=firstName]')
|
||||
.clear()
|
||||
.type('Seth');
|
||||
|
||||
// Update the last name
|
||||
cy.get('[data-testid=lastName]')
|
||||
.clear()
|
||||
.type('Call');
|
||||
|
||||
cy.wait(2000);
|
||||
});
|
||||
|
||||
cy.reload();
|
||||
|
||||
cy.get('[data-testid=firstName]').should('have.value', 'Seth');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('Payments Page', () => {
|
||||
beforeEach(() => {
|
||||
// Place any setup code here, such as logging in or navigating to the payments page
|
||||
const currentUser = makeFakeUser();
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.intercept('GET', /\S+\/invoice_history\?limit=10&cursor=0/, { fixture: 'payments_page1' }).as('getPayments1');
|
||||
cy.intercept('GET', /\S+\/invoice_history\?limit=10&cursor=10/, { fixture: 'payments_page2' }).as('getPayments2');
|
||||
cy.intercept('GET', /\S+\/invoice_history\?limit=10&cursor=20/, { fixture: 'payments_page3' }).as('getPayments3');
|
||||
});
|
||||
|
||||
describe('in desktop', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport('macbook-13');
|
||||
});
|
||||
|
||||
it('should list user\'s payments', () => {
|
||||
// Call the external API that fetches the payment records
|
||||
cy.visit('/account/payments')
|
||||
cy.wait('@getPayments1')
|
||||
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr td').first().within(() => {
|
||||
cy.contains('12/01/2022')
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
it('paginate through the payments', () => {
|
||||
// Call the external API that fetches the payment records
|
||||
cy.visit('/account/payments')
|
||||
cy.wait('@getPayments1')
|
||||
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr').first().within(() => {
|
||||
cy.contains('12/01/2022')
|
||||
})
|
||||
|
||||
// Click the next page button
|
||||
cy.get('[data-testid="nextPageButton"]').click()
|
||||
cy.wait('@getPayments2')
|
||||
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr:nth-child(11)').first().within(() => {
|
||||
cy.contains('02/01/2022')
|
||||
})
|
||||
|
||||
// Click the next page button
|
||||
cy.get('[data-testid="nextPageButton"]').click()
|
||||
cy.wait('@getPayments3')
|
||||
cy.get('[data-testid="paymentsListTable"]').should('be.visible').find('tbody tr:nth-child(22)').first().within(() => {
|
||||
cy.contains('03/01/2021')
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('in mobile', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport('iphone-6');
|
||||
});
|
||||
|
||||
it('should list user\'s payments', () => {
|
||||
// Call the external API that fetches the payment records
|
||||
cy.visit('/account/payments')
|
||||
cy.wait('@getPayments1')
|
||||
cy.get('[data-testid=paymentSwiper]').should('be.visible')
|
||||
|
||||
for (let i = 0; i < 9; i++) {
|
||||
cy.get('.swiper-button-next').click();
|
||||
cy.wait(500);
|
||||
}
|
||||
cy.wait('@getPayments2')
|
||||
for (let i = 0; i < 10; i++) {
|
||||
cy.get('.swiper-button-next').click();
|
||||
cy.wait(500);
|
||||
}
|
||||
cy.get('.swiper-button-next').click();
|
||||
cy.wait('@getPayments3')
|
||||
for (let i = 0; i < 2; i++) {
|
||||
cy.get('.swiper-button-next').click();
|
||||
cy.wait(500);
|
||||
}
|
||||
cy.get('.swiper-button-next').should('have.class', 'swiper-button-disabled');
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('Affiliate Earnings', () => {
|
||||
beforeEach(() => {
|
||||
const currentUser = makeFakeUser();
|
||||
cy.stubAuthenticate({ id: currentUser.id });
|
||||
cy.stubGonSubscriptionCodes();
|
||||
});
|
||||
|
||||
describe('When user has no earnings', () => {
|
||||
it('should show no earnings message', () => {
|
||||
cy.intercept('GET', /\S+\/api\/affiliate_partners\/payments/, {
|
||||
body: [
|
||||
{
|
||||
payments: [],
|
||||
next: null
|
||||
}
|
||||
]
|
||||
}).as('fetchAllEarnings');
|
||||
cy.visit('/affiliate/earnings');
|
||||
cy.wait('@fetchAllEarnings');
|
||||
cy.contains('There is no earnings data yet ');
|
||||
});
|
||||
});
|
||||
|
||||
describe('When user has earnings', () => {
|
||||
it('should show earnings', () => {
|
||||
cy.intercept('GET', /\S+\/api\/affiliate_partners\/payments/, {
|
||||
body: {
|
||||
payments: [
|
||||
{
|
||||
payment_type: 'monthly',
|
||||
year: 2021,
|
||||
month: 9,
|
||||
subscriptions: [
|
||||
{
|
||||
plan: 'jamsubsilver',
|
||||
count: 2
|
||||
}
|
||||
],
|
||||
jamtracks_sold: 3,
|
||||
due_amount_in_cents: 5000
|
||||
},
|
||||
{
|
||||
payment_type: 'monthly',
|
||||
year: 2021,
|
||||
month: 8,
|
||||
subscriptions: [
|
||||
{
|
||||
plan: 'jamsubgold',
|
||||
count: 1
|
||||
},
|
||||
{
|
||||
plan: 'jamsubplatinum',
|
||||
count: 2
|
||||
}
|
||||
],
|
||||
jamtracks_sold: 2,
|
||||
due_amount_in_cents: 3000
|
||||
}
|
||||
],
|
||||
next: null
|
||||
}
|
||||
}).as('fetchAllEarnings');
|
||||
cy.visit('/affiliate/earnings');
|
||||
cy.wait('@fetchAllEarnings');
|
||||
cy.get('[data-testid=affiliateEarningsList] tbody tr:first-child td')
|
||||
.eq(0)
|
||||
.should('have.text', 'September 2021');
|
||||
cy.get('[data-testid=affiliateEarningsList] tbody tr:first-child td')
|
||||
.eq(1)
|
||||
.should('have.text', 'Silver - 2');
|
||||
cy.get('[data-testid=affiliateEarningsList] tbody tr:first-child td')
|
||||
.eq(2)
|
||||
.should('have.text', '3');
|
||||
cy.get('[data-testid=affiliateEarningsList] tbody tr:first-child td')
|
||||
.eq(3)
|
||||
.should('have.text', '$50.00');
|
||||
});
|
||||
});
|
||||
|
||||
describe('in mobile', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('iphone-6');
|
||||
});
|
||||
|
||||
it('should show earnings', () => {
|
||||
cy.intercept('GET', /\S+\/api\/affiliate_partners\/payments/, {
|
||||
body: {
|
||||
payments: [
|
||||
{
|
||||
payment_type: 'monthly',
|
||||
year: 2021,
|
||||
month: 9,
|
||||
subscriptions: [
|
||||
{
|
||||
plan: 'jamsubsilver',
|
||||
count: 2
|
||||
}
|
||||
],
|
||||
jamtracks_sold: 3,
|
||||
due_amount_in_cents: 5000
|
||||
},
|
||||
{
|
||||
payment_type: 'monthly',
|
||||
year: 2021,
|
||||
month: 8,
|
||||
subscriptions: [
|
||||
{
|
||||
plan: 'jamsubgold',
|
||||
count: 1
|
||||
},
|
||||
{
|
||||
plan: 'jamsubplatinum',
|
||||
count: 2
|
||||
}
|
||||
],
|
||||
jamtracks_sold: 2,
|
||||
due_amount_in_cents: 3000
|
||||
}
|
||||
],
|
||||
next: null
|
||||
}
|
||||
}).as('fetchAllEarningsOnMobile');
|
||||
cy.visit('/affiliate/earnings');
|
||||
cy.wait('@fetchAllEarningsOnMobile');
|
||||
cy.contains('September 2021');
|
||||
cy.contains('Silver - 2');
|
||||
cy.contains('JamTracks Sold: 3');
|
||||
cy.contains('Earnings: $50.00');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import { day } from 'is_js';
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('affiliate signups', () => {
|
||||
beforeEach(() => {
|
||||
const currentUser = makeFakeUser();
|
||||
cy.stubAuthenticate({ id: currentUser.id });
|
||||
//cy.stubGonSubscriptionCodes();
|
||||
});
|
||||
|
||||
describe('when user has no signups', () => {
|
||||
it('should show no signups message', () => {
|
||||
cy.intercept('GET', /\S+\/api\/affiliate_partners\/signups?\S+/, {
|
||||
body: [
|
||||
{
|
||||
traffics: [],
|
||||
next: null
|
||||
}
|
||||
]
|
||||
}).as('fetchAllSignups');
|
||||
cy.visit('/affiliate/signups');
|
||||
cy.wait('@fetchAllSignups');
|
||||
cy.contains('There is no signup data yet ');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user has signups', () => {
|
||||
it('should show signups', () => {
|
||||
cy.intercept('GET', /\S+\/api\/affiliate_partners\/signups?\S+/, {
|
||||
body: {
|
||||
traffics: [
|
||||
{
|
||||
day: '2021-09-01',
|
||||
visits: 100,
|
||||
signups: 10,
|
||||
},
|
||||
{
|
||||
day: '2021-09-02',
|
||||
visits: 200,
|
||||
signups: 20,
|
||||
}
|
||||
]
|
||||
}
|
||||
}).as('fetchAllSignups');
|
||||
cy.visit('/affiliate/signups');
|
||||
cy.wait('@fetchAllSignups');
|
||||
cy.contains('Signups');
|
||||
cy.get('[data-testid=affiliateSignupList] tbody tr:first-child > td').eq(0).should('have.text', 'September 2021');
|
||||
cy.get('[data-testid=affiliateSignupList] tbody tr:first-child > td').eq(1).should('have.text', '300');
|
||||
cy.get('[data-testid=affiliateSignupList] tbody tr:first-child > td').eq(2).should('have.text', '30');
|
||||
});
|
||||
});
|
||||
|
||||
describe('in mobile', () => {
|
||||
it('should show signups in mobile', () => {
|
||||
cy.viewport('iphone-6');
|
||||
cy.intercept('GET', /\S+\/api\/affiliate_partners\/signups?\S+/, {
|
||||
body: {
|
||||
traffics: [
|
||||
{
|
||||
day: '2021-09-01',
|
||||
visits: 100,
|
||||
signups: 25,
|
||||
},
|
||||
{
|
||||
day: '2021-10-01',
|
||||
visits: 50,
|
||||
signups: 10,
|
||||
},
|
||||
{
|
||||
day: '2021-10-02',
|
||||
visits: 10,
|
||||
signups: 5,
|
||||
}
|
||||
]
|
||||
}
|
||||
}).as('fetchAllSignups');
|
||||
cy.visit('/affiliate/signups');
|
||||
cy.wait('@fetchAllSignups');
|
||||
cy.contains('Signups');
|
||||
cy.get('[data-testid=affiliateSignupsSwiper] .swiper-slide').should('have.length', 2);
|
||||
cy.get('[data-testid=affiliateSignupsSwiper] .swiper-button-next').click();
|
||||
cy.get('[data-testid=affiliateSignupsSwiper] .swiper-slide').contains('October 2021');
|
||||
cy.get('[data-testid=affiliateSignupsSwiper] .swiper-slide').contains('Visits: 60');
|
||||
cy.get('[data-testid=affiliateSignupsSwiper] .swiper-slide').contains('Signups: 15');
|
||||
});
|
||||
})
|
||||
})
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
///<reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('forgot password', () => {
|
||||
beforeEach(() => {
|
||||
const currentUser = makeFakeUser({
|
||||
email: 'sam@example.com'
|
||||
});
|
||||
cy.clearCookie('remeber_token');
|
||||
});
|
||||
|
||||
it('redirects to forgot password page', () => {
|
||||
cy.visit('/');
|
||||
cy.url().should('include', '/auth/login');
|
||||
cy.get('a')
|
||||
.contains('Forgot password?')
|
||||
.click();
|
||||
cy.url().should('include', '/auth/forget-password');
|
||||
cy.get('h5').contains('Forgot Your Password');
|
||||
});
|
||||
|
||||
describe('validate forgot password form', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/auth/forget-password');
|
||||
cy.get('[data-testid=email]').clear();
|
||||
cy.get('[data-testid=submit]').should('be.disabled');
|
||||
});
|
||||
|
||||
//invalid email format
|
||||
it('invalid email format', () => {
|
||||
cy.get('[data-testid=email]').type('invalid-email-format@example');
|
||||
cy.get('[data-testid=submit]').click();
|
||||
cy.url().should('not.include', /\/auth\/confirm-mail?\S+/);
|
||||
});
|
||||
|
||||
//valid email format but non-existing
|
||||
it('valid email format but non-existing', () => {
|
||||
cy.get('[data-testid=email]').type('valid-email-format@example.com');
|
||||
cy.get('[data-testid=submit]').click();
|
||||
cy.url().should('not.include', /\/auth\/confirm-mail?\S+/);
|
||||
});
|
||||
|
||||
//valid and existing email
|
||||
it('valid and existing email', () => {
|
||||
cy.get('[data-testid=email]').type('nuwan@jamkazam.com');
|
||||
cy.get('[data-testid=submit]').click();
|
||||
cy.wait(3000);
|
||||
cy.contains('Please check your email!');
|
||||
cy.url().should('match', /\S+auth\/confirm-mail?\S+/);
|
||||
cy.contains('An email has been sent to nuwan@jamkazam.com.')
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
///<reference types="cypress" />
|
||||
|
||||
function submitLogin(){
|
||||
const userAttrs = {
|
||||
id: '1',
|
||||
first_name: 'Peter',
|
||||
last_name: 'Pan',
|
||||
name: 'Peter Pan',
|
||||
photo_url: '',
|
||||
email: 'peter@example.com'
|
||||
}
|
||||
|
||||
cy.intercept('POST', `${Cypress.env('apiBaseUrl')}/auths/login`, {
|
||||
statusCode: 200,
|
||||
body: userAttrs
|
||||
}).as('createSession')
|
||||
|
||||
cy.intercept('GET', `${Cypress.env('apiBaseUrl')}/me`, {
|
||||
statusCode: 200,
|
||||
body: userAttrs
|
||||
}).as('getCurrentUser')
|
||||
|
||||
cy.reload()
|
||||
cy.get('[data-testid=email]').type('peter@example.com')
|
||||
cy.get('[data-testid=password]').type('jam123')
|
||||
cy.get('[data-testid=submit]').click()
|
||||
|
||||
}
|
||||
|
||||
describe('Unauthenticated users redirect to login page', () => {
|
||||
it('redirects to login page', () => {
|
||||
cy.clearCookie('remeber_token')
|
||||
cy.visit('/')
|
||||
cy.url().should('include', '/auth/login')
|
||||
cy.contains('Sign In')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Login page', () => {
|
||||
before(() => {
|
||||
cy.clearCookie('remeber_token')
|
||||
})
|
||||
|
||||
it('validate login form', () => {
|
||||
cy.visit('/auth/login')
|
||||
cy.reload()
|
||||
cy.get('[data-testid=submit]').should('be.disabled')
|
||||
cy.get('[data-testid=email]').type('invalid-email-format@example')
|
||||
cy.get('[data-testid=submit]').should('be.disabled')
|
||||
cy.get('[data-testid=email]').type('valid-email-format@example.com')
|
||||
cy.get('[data-testid=submit]').should('be.disabled')
|
||||
cy.get('[data-testid=password]').type('password')
|
||||
cy.get('[data-testid=submit]').should('not.be.disabled')
|
||||
})
|
||||
|
||||
it('submit login form with invalid credentials', () => {
|
||||
cy.visit('/auth/login')
|
||||
cy.reload()
|
||||
cy.get('[data-testid=email]').type('peter@example.com')
|
||||
cy.get('[data-testid=password]').type('wrong')
|
||||
cy.get('[data-testid=submit]').click()
|
||||
cy.contains('Incorrect email or password')
|
||||
})
|
||||
|
||||
it('submits login form', () => {
|
||||
cy.visit('/auth/login')
|
||||
submitLogin()
|
||||
cy.url().should('eq', Cypress.config().baseUrl + '/') // tests won't fail in case the port changes
|
||||
//cy.contains('Signed in as peter@example.com')
|
||||
//cy.contains('Peter Pan')
|
||||
//cy.getCookie('remember_token').should('exist')
|
||||
})
|
||||
|
||||
it('redirect to requested page', () => {
|
||||
cy.visit('/friends')
|
||||
cy.url().should('include', '/auth/login')
|
||||
cy.reload()
|
||||
submitLogin()
|
||||
cy.url().should('eq', Cypress.config().baseUrl + '/friends')
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('Forget password page', () => {
|
||||
it('submit forget password form', () => {
|
||||
cy.visit('/auth/forget-password')
|
||||
cy.get('[data-testid=email]').type('peter@example.com')
|
||||
cy.get('[data-testid=submit]').click()
|
||||
cy.contains('An email is sent')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -1,611 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
const showSidePanelContent = () => {
|
||||
cy.get('[data-testid=profileSidePanel] h4').should('have.text', 'Test User1');
|
||||
cy.get('[data-testid=profileSidePanel] .modal-body').first().within(() => {
|
||||
cy.contains('Location: Denver, CO, US')
|
||||
.and('contain', 'Skill Level: Professional')
|
||||
.and('contain', 'Joined JamKazam: 08-26-2021')
|
||||
.and('contain', 'Last Active:')
|
||||
.and('contain', 'Latency To Me:');
|
||||
cy.get('.latency-badge').contains('UNKNOWN');
|
||||
|
||||
cy.get('[data-testid=biography]').contains('Biography of Test User1');
|
||||
|
||||
//instruments
|
||||
cy.get('[data-testid=instruments]').contains('Acoustic Guitar: Expert');
|
||||
cy.get('[data-testid=instruments]').contains('Keyboard: Expert');
|
||||
|
||||
//genres
|
||||
cy.get('[data-testid=genres]').contains('classical, blues');
|
||||
|
||||
//bands
|
||||
cy.get('[data-testid=bands]').contains('The Band');
|
||||
|
||||
//performance_samples
|
||||
cy.get('[data-testid=performance_samples]').contains('Test Recording1')//.should('have.attr', 'href').and('eq', 'https://www.jamkazam.com/test-recording1');
|
||||
|
||||
//online presence
|
||||
cy.get('[data-testid=online_presences]').contains('Youtube').should('have.attr', 'href').and('eq', 'https://www.youtube.com/testuser');
|
||||
cy.get('[data-testid=online_presences]').contains('Facebook').should('have.attr', 'href').and('eq', 'https://www.facebook.com/testuser');
|
||||
cy.get('[data-testid=online_presences]').contains('Twitter').should('have.attr', 'href').and('eq', 'https://www.twitter.com/testuser');
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const closeSidePanel = () => {
|
||||
cy.get('[data-testid=profileSidePanel] .modal-header button.close').click();
|
||||
};
|
||||
|
||||
describe('Friends page without data', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
cy.intercept('POST', /\S+\/filter/, {
|
||||
musicians: []
|
||||
}).as("getPeople_empty");
|
||||
});
|
||||
|
||||
//from_location checkbox is hidden for now. so we skip this test for now
|
||||
it.skip('from_location is unchecked', () => {
|
||||
cy.visit('/friends');
|
||||
|
||||
//default api call with from_location parameter turned off
|
||||
cy.wait('@getPeople_empty')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '1st API call');
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.contain', {
|
||||
from_location: false
|
||||
});
|
||||
|
||||
//now it automatically turns on from_location parameter and fetches again
|
||||
cy.wait('@getPeople_empty')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '2nd API call - (prefetched)');
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.contain', {
|
||||
from_location: true
|
||||
});
|
||||
|
||||
cy.contains('No Records!');
|
||||
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=from_location]').check();
|
||||
cy.wait(1000);
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
//default api call with from_location parameter turned on
|
||||
cy.wait('@getPeople_empty')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '3th API call');
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.contain', {
|
||||
from_location: true
|
||||
});
|
||||
|
||||
cy.contains('No Records!');
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('Friends page with data', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate({ id: '2' }); //currentUser id is 2 - people.yaml fixture
|
||||
cy.intercept('POST', /\S+\/filter\?offset=0/, { fixture: 'people_page1' }).as('getPeople_page1');
|
||||
cy.intercept('POST', /\S+\/filter\?offset=10/, { fixture: 'people_page2' }).as('getPeople_page2');
|
||||
cy.intercept('POST', /\S+\/filter\?offset=20/, { fixture: 'people_page3' }).as('getPeople_page3');
|
||||
cy.intercept('GET', /\S+\/profile/, { fixture: 'person' });
|
||||
cy.intercept('GET', /\S+\/my_notifications\S+/, {
|
||||
statusCode: 200,
|
||||
body: []
|
||||
});
|
||||
});
|
||||
|
||||
describe('listing users', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
||||
describe('in desktop', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('macbook-13');
|
||||
});
|
||||
|
||||
it('paginate', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 10);
|
||||
cy.wait('@getPeople_page2')
|
||||
cy.get('[data-testid=paginate-next-page]').click();
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 20);
|
||||
cy.get('[data-testid=paginate-next-page]').click();
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 30);
|
||||
cy.get('[data-testid=paginate-next-page]').should('not.exist');
|
||||
});
|
||||
|
||||
it('show profiles', () => {
|
||||
cy.contains('Find New Friends').should('exist');
|
||||
cy.contains('Update Search').should('exist');
|
||||
cy.contains('Reset Filters').should('exist');
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.should('have.length', 10)
|
||||
.first()
|
||||
.contains('Test User1');
|
||||
});
|
||||
|
||||
it('click profile name', () => {
|
||||
//open side panel by clicking name
|
||||
cy.get('[data-testid=peopleListTable]').find('.person-link').first().within(() => {
|
||||
cy.contains("Test User1").click()
|
||||
})
|
||||
//cy.get('[data-testid=peopleListTable]').find('.person-link').first().click()
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click more button', () => {
|
||||
//open side panel by clicking more button
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click more link', () => {
|
||||
//open side panel by clicking more link
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=linkMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click description more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('td[data-testid=biography-col]')
|
||||
.within(() => {
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click instruments more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=instrumentList]')
|
||||
.within(() => {
|
||||
cy.get('[data-testid=instrument]').should('have.length', 4); //show only 4 instruments plus more link
|
||||
cy.contains('Acoustic Guitar: Expert');
|
||||
cy.contains('Keyboard: Expert');
|
||||
cy.contains('Ukulele: Expert');
|
||||
cy.contains('Voice: Expert');
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click genres more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('td[data-testid=genres-col]')
|
||||
.within(() => {
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('in mobile', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('iphone-6');
|
||||
});
|
||||
|
||||
it('show profile', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').should('have.length', 10);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.eq(0)
|
||||
.contains('Test User1');
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.eq(0)
|
||||
.should('be.visible');
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.eq(2)
|
||||
.should('not.be.visible');
|
||||
});
|
||||
|
||||
it('show all profile description', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=mobBiography]')
|
||||
.should('not.contain', 'More');
|
||||
});
|
||||
|
||||
it('show all instruments', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=instrumentList] div')
|
||||
.its('length')
|
||||
.should('be.gte', 1);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=instrumentList]')
|
||||
.should('not.contain', 'More');
|
||||
});
|
||||
|
||||
it('show all genres', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=genreList] div')
|
||||
.its('length')
|
||||
.should('be.gte', 1);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=genreList]')
|
||||
.should('not.contain', 'More');
|
||||
});
|
||||
|
||||
//it.skip('click connect button', () => {});
|
||||
|
||||
//it.skip('click message button', () => {});
|
||||
|
||||
it.skip('paginate', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-prev').should('have.class', 'swiper-button-disabled');
|
||||
for (let i = 0; i < 19; i++) {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-next').click();
|
||||
cy.wait(500);
|
||||
}
|
||||
cy.wait(500);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-next').should('have.class', 'swiper-button-disabled');
|
||||
});
|
||||
|
||||
it('click more button', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('making friendship', () => {
|
||||
it('add friend', () => {
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });
|
||||
|
||||
cy.visit('/friends');
|
||||
cy.contains('Test User2').click();
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
// cy.get('[data-testid=confirmFriendRequestModal]').within(() => {
|
||||
// cy.contains('Send a friend request to Test User2');
|
||||
// cy.contains('Yes').click();
|
||||
// });
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('be.disabled');
|
||||
cy.contains('Success! Your friend request has been sent to Test User2.');
|
||||
});
|
||||
|
||||
it('remove friend', () => {
|
||||
cy.intercept('GET', /\S+\/profile/, { fixture: 'friend' });
|
||||
cy.intercept('DELETE', /\S+\/friends\S+/, { statusCode: 204, body: { ok: true } });
|
||||
|
||||
cy.visit('/friends');
|
||||
cy.contains('Test User1').click();
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=disconnect]')
|
||||
.should('exist')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=disconnect]')
|
||||
.should('not.exist');
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('be.exist')
|
||||
.should('not.be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('chat window', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
||||
it('is not disabled for friends', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.should('not.be.disabled')
|
||||
.trigger('mouseover');
|
||||
cy.contains('Send a message').should('exist');
|
||||
});
|
||||
|
||||
it('is not disabled for non friends', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(1)
|
||||
.find('[data-testid=message]')
|
||||
.should('not.be.disabled');
|
||||
//cy.contains('You can message this user once you are friends').should('exist')
|
||||
});
|
||||
|
||||
it('lists text messages', () => {
|
||||
//initially show the most recent messages on openning chat window modal
|
||||
let numberOfMessages = 10;
|
||||
cy.fixture('text_messages_page1').then(json => {
|
||||
cy.intercept('GET', /\S+\/text_messages\S+/, json).as('getTextMessages');
|
||||
});
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.wait('@getTextMessages');
|
||||
cy.get('[data-testid=textMessageModal]')
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get('.text-message-row').should('have.length', numberOfMessages);
|
||||
|
||||
//display previous messages by scrolling up
|
||||
const messageFixtures = ['text_messages_page2', 'text_messages_page3'];
|
||||
messageFixtures.forEach(fixture => {
|
||||
cy.fixture(fixture).then(json => {
|
||||
cy.intercept('GET', /\S+\/text_messages\S+/, json);
|
||||
cy.get('.modal-body .ScrollbarsCustom-Scroller')
|
||||
.trigger('mouseover')
|
||||
.scrollTo('bottom');
|
||||
cy.get('.modal-body .ScrollbarsCustom-Scroller')
|
||||
.trigger('mouseover')
|
||||
.scrollTo('top');
|
||||
numberOfMessages = numberOfMessages + 10;
|
||||
cy.get('.text-message-row').should('have.length', numberOfMessages);
|
||||
});
|
||||
});
|
||||
|
||||
cy.get('button')
|
||||
.contains('Close')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
});
|
||||
cy.get('[data-testid=textMessageModal]').should('not.be.visible');
|
||||
});
|
||||
|
||||
it('sends message by clicking send button', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.get('[data-testid=textMessageModal]').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
cy.get('textarea').type('Hello');
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
cy.get('textarea').should('have.value', '');
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('sends message by pressing enter key', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.get('[data-testid=textMessageModal]').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
cy.get('textarea').type('Hello{enter}');
|
||||
cy.get('textarea').should('have.value', '');
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('goes away by clicking close button', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.get('[data-testid=textMessageModal]').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Close')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
});
|
||||
cy.get('[data-testid=textMessageModal]').should('not.be.visible');
|
||||
});
|
||||
|
||||
it.skip('shows received message by other user', () => {
|
||||
//TODO: this should be test in e2e test
|
||||
});
|
||||
});
|
||||
|
||||
describe('coming from email links', () => {
|
||||
it("opens details sidebar", () => {
|
||||
cy.visit('/friends?open=details&id=1');
|
||||
showSidePanelContent();
|
||||
});
|
||||
|
||||
it("opens chat window", () => {
|
||||
cy.visit('/friends?open=message&id=1');
|
||||
cy.get('[data-testid=textMessageModal]')
|
||||
.should('be.visible')
|
||||
cy.contains('Send Message to Test User1').should('exist');
|
||||
});
|
||||
|
||||
it("sends friend request", () => {
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });
|
||||
cy.visit('/friends?open=connect&id=1');
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('be.disabled');
|
||||
cy.contains('Success! Your friend request has been sent to Test User1.');
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
describe('filter', () => {
|
||||
const fillFilterForm = () => {
|
||||
//cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_fair]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_high]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_beginner]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_intermediate]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_expert]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_expert]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=from_location]').uncheck();
|
||||
cy.get('#selInstruments')
|
||||
.type('Drums{enter}')
|
||||
.click();
|
||||
cy.get('#selGenres')
|
||||
.type('Pop{enter}')
|
||||
.click();
|
||||
cy.get('#selLastActive').type('Within last 1 Day{enter}');
|
||||
cy.get('#selJoinedWithin').type('Within last 7 Day{enter}');
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
||||
it('open and close filter modal', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch]').should('be.visible');
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=modalUpdateSearch]').should('not.be.visible');
|
||||
});
|
||||
|
||||
it('render filter form', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch]').within(() => {
|
||||
cy.get('input[name=latency_good]')
|
||||
.should('be.checked')
|
||||
.next()
|
||||
.contains('Good (less than 40ms)');
|
||||
cy.get('input[name=latency_fair]')
|
||||
.should('be.checked')
|
||||
.next()
|
||||
.contains('Fair (40-60ms)');
|
||||
cy.get('input[name=latency_high]')
|
||||
.should('not.be.checked')
|
||||
.next()
|
||||
.contains('Poor (more than 60ms)');
|
||||
cy.get('input[name=from_location]')
|
||||
.should('not.be.checked')
|
||||
});
|
||||
});
|
||||
|
||||
it('reset filters', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm();
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('not.be.checked');
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=btnResetSearch]').click(); //click reset button
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('be.checked');
|
||||
});
|
||||
|
||||
it('submit filter form with params', () => {
|
||||
//wait for stubbed request sent to fetch data for initial page load
|
||||
cy.wait('@getPeople_page1').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '1st API call has data');
|
||||
});
|
||||
//the subsequent request sent to perfetch data and store in redux prefetched buffer
|
||||
cy.wait('@getPeople_page2').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '1st API call has data - (prefethed)');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.wait(1000);
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
//wait for stubbed request sent by submitting search form without filling any form field
|
||||
cy.wait('@getPeople_page1')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '3rd API call has data');
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.contain', {
|
||||
latency_good: true,
|
||||
latency_fair: true,
|
||||
latency_high: false,
|
||||
proficiency_beginner: true,
|
||||
proficiency_intermediate: true,
|
||||
proficiency_expert: true,
|
||||
instruments: [],
|
||||
genres: [],
|
||||
from_location: false
|
||||
});
|
||||
|
||||
cy.wait('@getPeople_page2').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '4th API call has data - (prefethed)');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm(); // change filter options
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
//wait for stubbed request sent by submitting search form again. but this time fill form fields
|
||||
cy.wait('@getPeople_page1')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '5th API call has data');
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.contain', {
|
||||
latency_good: false,
|
||||
latency_fair: false,
|
||||
latency_high: false,
|
||||
proficiency_beginner: false,
|
||||
proficiency_intermediate: false,
|
||||
proficiency_expert: false,
|
||||
instruments: [{ value: 'drums', label: 'Drums' }],
|
||||
genres: ['pop'],
|
||||
from_location: false
|
||||
});
|
||||
|
||||
cy.wait('@getPeople_page2').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '6th API call has data - (prefethed)');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,607 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
const showSidePanelContent = () => {
|
||||
cy.get('[data-testid=profileSidePanel] h4').should('have.text', 'Test User1');
|
||||
cy.get('[data-testid=profileSidePanel] .modal-body').first().within(() => {
|
||||
cy.contains('Location: Denver, CO, US')
|
||||
.and('contain', 'Skill Level: Professional')
|
||||
.and('contain', 'Joined JamKazam: 08-26-2021')
|
||||
.and('contain', 'Last Active:')
|
||||
.and('contain', 'Latency To Me:');
|
||||
cy.get('.latency-badge').contains('UNKNOWN');
|
||||
|
||||
cy.get('[data-testid=biography]').contains('Biography of Test User1');
|
||||
|
||||
//instruments
|
||||
cy.get('[data-testid=instruments]').contains('Acoustic Guitar: Expert');
|
||||
cy.get('[data-testid=instruments]').contains('Keyboard: Expert');
|
||||
|
||||
//genres
|
||||
cy.get('[data-testid=genres]').contains('classical, blues');
|
||||
|
||||
//bands
|
||||
cy.get('[data-testid=bands]').contains('The Band');
|
||||
|
||||
//performance_samples
|
||||
cy.get('[data-testid=performance_samples]').contains('Test Recording1')//.should('have.attr', 'href').and('eq', 'https://www.jamkazam.com/test-recording1');
|
||||
|
||||
//online presence
|
||||
cy.get('[data-testid=online_presences]').contains('Youtube').should('have.attr', 'href').and('eq', 'https://www.youtube.com/testuser');
|
||||
cy.get('[data-testid=online_presences]').contains('Facebook').should('have.attr', 'href').and('eq', 'https://www.facebook.com/testuser');
|
||||
cy.get('[data-testid=online_presences]').contains('Twitter').should('have.attr', 'href').and('eq', 'https://www.twitter.com/testuser');
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const closeSidePanel = () => {
|
||||
cy.get('[data-testid=profileSidePanel] .modal-header button.close').click();
|
||||
};
|
||||
|
||||
describe('Friends page without data', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
// cy.intercept('POST', /\S+\/filter/, {
|
||||
// musicians: []
|
||||
// }).as("getPeople_empty");
|
||||
});
|
||||
|
||||
it('shows no records found alert', () => {
|
||||
cy.visit('/friends/my');
|
||||
|
||||
//default api call with from_location parameter turned off
|
||||
// cy.wait('@getPeople_empty')
|
||||
// .then(interception => {
|
||||
// assert.isNotNull(interception.response.body, '1st API call');
|
||||
// })
|
||||
// .its('request.body')
|
||||
// .should('deep.contain', {
|
||||
// from_location: false
|
||||
// });
|
||||
|
||||
// //now it automatically turns on from_location parameter and fetches again
|
||||
// cy.wait('@getPeople_empty')
|
||||
// .then(interception => {
|
||||
// assert.isNotNull(interception.response.body, '2nd API call - (prefetched)');
|
||||
// })
|
||||
// .its('request.body')
|
||||
// .should('deep.contain', {
|
||||
// from_location: true
|
||||
// });
|
||||
|
||||
// cy.contains('No Records!');
|
||||
|
||||
// cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
// cy.get('[data-testid=modalUpdateSearch] input[name=from_location]').check();
|
||||
// cy.wait(1000);
|
||||
// cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
// //default api call with from_location parameter turned on
|
||||
// cy.wait('@getPeople_empty')
|
||||
// .then(interception => {
|
||||
// assert.isNotNull(interception.response.body, '3th API call');
|
||||
// })
|
||||
// .its('request.body')
|
||||
// .should('deep.contain', {
|
||||
// from_location: true
|
||||
// });
|
||||
|
||||
// cy.contains('No Records!');
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('Friends page with data', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate({ id: '2' }); //currentUser id is 2 - people.yaml fixture
|
||||
cy.intercept('POST', /\S+\/filter\?offset=0/, { fixture: 'people_page1' }).as('getPeople_page1');
|
||||
cy.intercept('POST', /\S+\/filter\?offset=10/, { fixture: 'people_page2' }).as('getPeople_page2');
|
||||
cy.intercept('POST', /\S+\/filter\?offset=20/, { fixture: 'people_page3' }).as('getPeople_page3');
|
||||
cy.intercept('GET', /\S+\/profile/, { fixture: 'person' });
|
||||
});
|
||||
|
||||
describe('listing users', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
||||
describe('in desktop', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('macbook-13');
|
||||
});
|
||||
|
||||
it('paginate', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 10);
|
||||
cy.wait('@getPeople_page2')
|
||||
cy.get('[data-testid=paginate-next-page]').click();
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 20);
|
||||
//cy.get('[data-testid=paginate-next-page]').should('not.exist');
|
||||
cy.get('[data-testid=paginate-next-page]').click();
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 30);
|
||||
cy.get('[data-testid=paginate-next-page]').should('not.exist');
|
||||
});
|
||||
|
||||
it('show profiles', () => {
|
||||
cy.contains('Find New Friends').should('exist');
|
||||
cy.contains('Update Search').should('exist');
|
||||
cy.contains('Reset Filters').should('exist');
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.should('have.length', 10)
|
||||
.first()
|
||||
.contains('Test User1');
|
||||
});
|
||||
|
||||
it('click profile name', () => {
|
||||
//open side panel by clicking name
|
||||
cy.get('[data-testid=peopleListTable]').find('.person-link').first().within(() => {
|
||||
cy.contains("Test User1").click()
|
||||
})
|
||||
//cy.get('[data-testid=peopleListTable]').find('.person-link').first().click()
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click more button', () => {
|
||||
//open side panel by clicking more button
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click more link', () => {
|
||||
//open side panel by clicking more link
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=linkMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click description more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('td[data-testid=biography-col]')
|
||||
.within(() => {
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click instruments more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('[data-testid=instrumentList]')
|
||||
.within(() => {
|
||||
cy.get('[data-testid=instrument]').should('have.length', 4); //show only 4 instruments plus more link
|
||||
cy.contains('Acoustic Guitar: Expert');
|
||||
cy.contains('Keyboard: Expert');
|
||||
cy.contains('Ukulele: Expert');
|
||||
cy.contains('Voice: Expert');
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
it('click genres more link', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.first()
|
||||
.find('td[data-testid=genres-col]')
|
||||
.within(() => {
|
||||
cy.contains('More').click();
|
||||
});
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('in mobile', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('iphone-6');
|
||||
});
|
||||
|
||||
it('show profile', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide').should('have.length', 10);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.eq(0)
|
||||
.contains('Test User1');
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.eq(0)
|
||||
.should('be.visible');
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.eq(2)
|
||||
.should('not.be.visible');
|
||||
});
|
||||
|
||||
it('show all profile description', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=mobBiography]')
|
||||
.should('not.contain', 'More');
|
||||
});
|
||||
|
||||
it('show all instruments', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=instrumentList] div')
|
||||
.its('length')
|
||||
.should('be.gte', 1);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=instrumentList]')
|
||||
.should('not.contain', 'More');
|
||||
});
|
||||
|
||||
it('show all genres', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=genreList] div')
|
||||
.its('length')
|
||||
.should('be.gte', 1);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=genreList]')
|
||||
.should('not.contain', 'More');
|
||||
});
|
||||
|
||||
//it.skip('click connect button', () => {});
|
||||
|
||||
//it.skip('click message button', () => {});
|
||||
|
||||
it.skip('paginate', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-prev').should('have.class', 'swiper-button-disabled');
|
||||
for (let i = 0; i < 19; i++) {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-next').click();
|
||||
cy.wait(500);
|
||||
}
|
||||
cy.wait(500);
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-button-next').should('have.class', 'swiper-button-disabled');
|
||||
});
|
||||
|
||||
it('click more button', () => {
|
||||
cy.get('[data-testid=peopleSwiper] .swiper-slide')
|
||||
.first()
|
||||
.find('[data-testid=btnMore]')
|
||||
.click();
|
||||
showSidePanelContent();
|
||||
closeSidePanel();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('making friendship', () => {
|
||||
it('add friend', () => {
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });
|
||||
|
||||
cy.visit('/friends');
|
||||
cy.contains('Test User2').click();
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
// cy.get('[data-testid=confirmFriendRequestModal]').within(() => {
|
||||
// cy.contains('Send a friend request to Test User2');
|
||||
// cy.contains('Yes').click();
|
||||
// });
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('be.disabled');
|
||||
cy.contains('Success! Your friend request has been sent to Test User2.');
|
||||
});
|
||||
|
||||
it('remove friend', () => {
|
||||
cy.intercept('GET', /\S+\/profile/, { fixture: 'friend' });
|
||||
cy.intercept('DELETE', /\S+\/friends\S+/, { statusCode: 204, body: { ok: true } });
|
||||
|
||||
cy.visit('/friends');
|
||||
cy.contains('Test User1').click();
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=disconnect]')
|
||||
.should('exist')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=disconnect]')
|
||||
.should('not.exist');
|
||||
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('be.exist')
|
||||
.should('not.be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('chat window', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
||||
it('is not disabled for friends', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.should('not.be.disabled')
|
||||
.trigger('mouseover');
|
||||
cy.contains('Send a message').should('exist');
|
||||
});
|
||||
|
||||
it('is not disabled for non friends', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(1)
|
||||
.find('[data-testid=message]')
|
||||
.should('not.be.disabled');
|
||||
//cy.contains('You can message this user once you are friends').should('exist')
|
||||
});
|
||||
|
||||
it('lists text messages', () => {
|
||||
//initially show the most recent messages on openning chat window modal
|
||||
let numberOfMessages = 10;
|
||||
cy.fixture('text_messages_page1').then(json => {
|
||||
cy.intercept('GET', /\S+\/text_messages\S+/, json).as('getTextMessages');
|
||||
});
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.wait('@getTextMessages');
|
||||
cy.get('[data-testid=textMessageModal]')
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get('.text-message-row').should('have.length', numberOfMessages);
|
||||
|
||||
//display previous messages by scrolling up
|
||||
const messageFixtures = ['text_messages_page2', 'text_messages_page3'];
|
||||
messageFixtures.forEach(fixture => {
|
||||
cy.fixture(fixture).then(json => {
|
||||
cy.intercept('GET', /\S+\/text_messages\S+/, json);
|
||||
cy.get('.modal-body .ScrollbarsCustom-Scroller')
|
||||
.trigger('mouseover')
|
||||
.scrollTo('bottom');
|
||||
cy.get('.modal-body .ScrollbarsCustom-Scroller')
|
||||
.trigger('mouseover')
|
||||
.scrollTo('top');
|
||||
numberOfMessages = numberOfMessages + 10;
|
||||
cy.get('.text-message-row').should('have.length', numberOfMessages);
|
||||
});
|
||||
});
|
||||
|
||||
cy.get('button')
|
||||
.contains('Close')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
});
|
||||
cy.get('[data-testid=textMessageModal]').should('not.be.visible');
|
||||
});
|
||||
|
||||
it('sends message by clicking send button', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.get('[data-testid=textMessageModal]').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
cy.get('textarea').type('Hello');
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
cy.get('textarea').should('have.value', '');
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('sends message by pressing enter key', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.get('[data-testid=textMessageModal]').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
cy.get('textarea').type('Hello{enter}');
|
||||
cy.get('textarea').should('have.value', '');
|
||||
cy.get('button')
|
||||
.contains('Send')
|
||||
.should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('goes away by clicking close button', () => {
|
||||
cy.get('[data-testid=peopleListTable] > tbody tr')
|
||||
.eq(0)
|
||||
.find('[data-testid=message]')
|
||||
.click();
|
||||
cy.get('[data-testid=textMessageModal]').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Close')
|
||||
.should('not.be.disabled')
|
||||
.click();
|
||||
});
|
||||
cy.get('[data-testid=textMessageModal]').should('not.be.visible');
|
||||
});
|
||||
|
||||
it.skip('shows received message by other user', () => {
|
||||
//TODO: this should be test in e2e test
|
||||
});
|
||||
});
|
||||
|
||||
describe('coming from email links', () => {
|
||||
it("opens details sidebar", () => {
|
||||
cy.visit('/friends?open=details&id=1');
|
||||
showSidePanelContent();
|
||||
});
|
||||
|
||||
it("opens chat window", () => {
|
||||
cy.visit('/friends?open=message&id=1');
|
||||
cy.get('[data-testid=textMessageModal]')
|
||||
.should('be.visible')
|
||||
cy.contains('Send Message to Test User1').should('exist');
|
||||
});
|
||||
|
||||
it("sends friend request", () => {
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });
|
||||
cy.visit('/friends?open=connect&id=1');
|
||||
cy.get('[data-testid=profileSidePanel]')
|
||||
.find('[data-testid=connect]')
|
||||
.should('be.disabled');
|
||||
cy.contains('Success! Your friend request has been sent to Test User1.');
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
describe('filter', () => {
|
||||
const fillFilterForm = () => {
|
||||
//cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_fair]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_high]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_beginner]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_intermediate]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_expert]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_expert]').uncheck();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=from_location]').uncheck();
|
||||
cy.get('#selInstruments')
|
||||
.type('Drums{enter}')
|
||||
.click();
|
||||
cy.get('#selGenres')
|
||||
.type('Pop{enter}')
|
||||
.click();
|
||||
cy.get('#selLastActive').type('Within last 1 Day{enter}');
|
||||
cy.get('#selJoinedWithin').type('Within last 7 Day{enter}');
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit('/friends');
|
||||
});
|
||||
|
||||
it('open and close filter modal', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch]').should('be.visible');
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=modalUpdateSearch]').should('not.be.visible');
|
||||
});
|
||||
|
||||
it('render filter form', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch]').within(() => {
|
||||
cy.get('input[name=latency_good]')
|
||||
.should('be.checked')
|
||||
.next()
|
||||
.contains('Good (less than 40ms)');
|
||||
cy.get('input[name=latency_fair]')
|
||||
.should('be.checked')
|
||||
.next()
|
||||
.contains('Fair (40-60ms)');
|
||||
cy.get('input[name=latency_high]')
|
||||
.should('not.be.checked')
|
||||
.next()
|
||||
.contains('Poor (more than 60ms)');
|
||||
cy.get('input[name=from_location]')
|
||||
.should('not.be.checked')
|
||||
});
|
||||
});
|
||||
|
||||
it('reset filters', () => {
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm();
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('not.be.checked');
|
||||
cy.get('[data-testid=modalUpdateSearch]')
|
||||
.contains('Cancel')
|
||||
.click();
|
||||
cy.get('[data-testid=btnResetSearch]').click(); //click reset button
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('be.checked');
|
||||
});
|
||||
|
||||
it('submit filter form with params', () => {
|
||||
//wait for stubbed request sent to fetch data for initial page load
|
||||
cy.wait('@getPeople_page1').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '1st API call has data');
|
||||
});
|
||||
//the subsequent request sent to perfetch data and store in redux prefetched buffer
|
||||
cy.wait('@getPeople_page2').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '1st API call has data - (prefethed)');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
cy.wait(1000);
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
//wait for stubbed request sent by submitting search form without filling any form field
|
||||
cy.wait('@getPeople_page1')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '3rd API call has data');
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.contain', {
|
||||
latency_good: true,
|
||||
latency_fair: true,
|
||||
latency_high: false,
|
||||
proficiency_beginner: true,
|
||||
proficiency_intermediate: true,
|
||||
proficiency_expert: true,
|
||||
instruments: [],
|
||||
genres: [],
|
||||
from_location: false
|
||||
});
|
||||
|
||||
cy.wait('@getPeople_page2').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '4th API call has data - (prefethed)');
|
||||
});
|
||||
|
||||
cy.get('[data-testid=btnUpdateSearch]').click();
|
||||
fillFilterForm(); // change filter options
|
||||
cy.get('[data-testid=btnSubmitSearch]').click();
|
||||
|
||||
//wait for stubbed request sent by submitting search form again. but this time fill form fields
|
||||
cy.wait('@getPeople_page1')
|
||||
.then(interception => {
|
||||
assert.isNotNull(interception.response.body, '5th API call has data');
|
||||
})
|
||||
.its('request.body')
|
||||
.should('deep.contain', {
|
||||
latency_good: false,
|
||||
latency_fair: false,
|
||||
latency_high: false,
|
||||
proficiency_beginner: false,
|
||||
proficiency_intermediate: false,
|
||||
proficiency_expert: false,
|
||||
instruments: [{ value: 'drums', label: 'Drums' }],
|
||||
genres: ['pop'],
|
||||
from_location: false
|
||||
});
|
||||
|
||||
cy.wait('@getPeople_page2').then(interception => {
|
||||
assert.isNotNull(interception.response.body, '6th API call has data - (prefethed)');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('Unsubscribe from email link', () => {
|
||||
beforeEach(() => {
|
||||
// cy.intercept('POST', /\S+\/unsubscribe_user_match\/\S+/, { statusCode: 200, body: { ok: true } });
|
||||
const currentUser = makeFakeUser({
|
||||
email: 'sam@example.com'
|
||||
});
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.intercept('POST', /\S+\/unsubscribe\/\S+/, { statusCode: 200, body: { ok: true } });
|
||||
})
|
||||
|
||||
it("redirect to home page if tok is not provided", () => {
|
||||
cy.visit('/unsubscribe');
|
||||
cy.location('pathname').should('eq', '/errors/404');
|
||||
});
|
||||
|
||||
it("show unsubscribed message", () => {
|
||||
cy.visit('/unsubscribe/123');
|
||||
// cy.location('search')
|
||||
// .should('equal', '?tok=123')
|
||||
// .then((s) => new URLSearchParams(s))
|
||||
// .invoke('get', 'tok')
|
||||
// .should('equal', '123')
|
||||
cy.contains("You have successfully unsubscribed from JamKazam emails.").should('be.visible');
|
||||
cy.contains("Loading...").should('not.exist');
|
||||
});
|
||||
|
||||
})
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('JamTracks Page', () => {
|
||||
beforeEach(() => {
|
||||
const currentUser = makeFakeUser();
|
||||
cy.stubAuthenticate({ id: currentUser.id });
|
||||
cy.visit('/jamtracks');
|
||||
});
|
||||
|
||||
it('should display the JamTracks page', () => {
|
||||
cy.get('.card-header h5').should('contain', 'Find JamTracks');
|
||||
});
|
||||
|
||||
it('should display the download link', () => {
|
||||
cy.get('[data-testid=download-pdf]')
|
||||
.invoke('attr', 'href')
|
||||
.should('contain', 'https://s3.amazonaws.com/jamkazam-public/public/lists/all-jamkazam-jamtracks.pdf');
|
||||
});
|
||||
|
||||
it('should display the JamTracks search bar', () => {
|
||||
cy.get('input[type="search"]').should('exist');
|
||||
});
|
||||
|
||||
describe('search', () => {
|
||||
beforeEach(() => {
|
||||
//http://www.jamkazam.local:3000/api/jamtracks/autocomplete?match=ac+&limit=5
|
||||
// cy.intercept('GET', /S+\/jamtracks\/autocomplete\?match=ac\S+/, {
|
||||
// body: [{ artists: [{ original_artist: 'AC DC' }], songs: [] }]
|
||||
// }).as('getJamTracksAutoComplete');
|
||||
cy.intercept('GET', /\S+\/jamtracks\?per_page=10\&page=1\&\S+/, { fixture: 'jamtracks_page1' }).as('getJamTracks_page1');
|
||||
cy.intercept('GET', /\S+\/jamtracks\?per_page=10\&page=2\&\S+/, { fixture: 'jamtracks_page2' }).as('getJamTracks_page2');
|
||||
cy.intercept('GET', /\S+\/jamtracks\?per_page=10\&page=3\&\S+/, { fixture: 'jamtracks_page3' }).as('getJamTracks_page3');
|
||||
cy.intercept('GET', /\S+\/shopping_carts/, {
|
||||
statusCode: 200,
|
||||
body: []
|
||||
}).as('getShoppingCart');
|
||||
cy.intercept('POST', /\S+\/shopping_carts\/add_jamtrack/, {
|
||||
statusCode: 200,
|
||||
body: { id: 1,
|
||||
product_info: {
|
||||
total_price: 9.99
|
||||
}
|
||||
}
|
||||
}).as('addJamTrackToCart');
|
||||
cy.intercept('GET', /\S+\/jamtracks\/purchased/, {
|
||||
statusCode: 200,
|
||||
body: []
|
||||
}).as('getPurchasedJamTracks');
|
||||
})
|
||||
|
||||
it('should display the JamTracks', () => {
|
||||
cy.get('input[type="search"]').type('ba{enter}');
|
||||
cy.wait('@getJamTracks_page1');
|
||||
cy.contains('Search Results: JamTracks including "ba"');
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr:first .track-name-col').should('contain', 'Back in Black by AC DC');
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr:first .track-tracks-col .jamtrack-track:visible').should('have.length', 6);
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr:first .track-tracks-col').contains('Show all tracks').click();
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr:first .track-tracks-col .jamtrack-track:visible').should('have.length', 10);
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr:first .track-tracks-col').contains('Show fewer tracks').click();
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr:first .track-tracks-col .jamtrack-track:visible').should('have.length', 6);
|
||||
|
||||
//load more
|
||||
cy.get('button').contains('Load More').click();
|
||||
cy.wait('@getJamTracks_page2');
|
||||
|
||||
//load more
|
||||
cy.get('button').contains('Load More').click();
|
||||
cy.wait('@getJamTracks_page3');
|
||||
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr').should('have.length', 30);
|
||||
|
||||
//no more pages
|
||||
cy.get('[data-testid=moreBtn]').should('not.exist');
|
||||
});
|
||||
|
||||
it('let user to purchase a JamTrack', () => {
|
||||
cy.get('input[type="search"]').type('ba{enter}');
|
||||
cy.wait('@getJamTracks_page1');
|
||||
cy.wait('@getShoppingCart');
|
||||
cy.get('[data-testid=jamtracks-table] tbody tr').eq(2).find('.purchase-button-col button').should('contain', 'Add to Cart').click();
|
||||
cy.wait('@getShoppingCart');
|
||||
cy.wait('@addJamTrackToCart');
|
||||
cy.location('pathname').should('eq', '/shopping-cart')
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe.only('mobile', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('iphone-6');
|
||||
});
|
||||
|
||||
it('should display the JamTracks', () => {
|
||||
cy.get('input[type="search"]').type('ba{enter}');
|
||||
cy.wait('@getJamTracks_page1');
|
||||
cy.contains('Search Results: JamTracks including "ba"');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('JamTracks Page', () => {
|
||||
beforeEach(() => {
|
||||
const currentUser = makeFakeUser();
|
||||
cy.stubAuthenticate({ id: currentUser.id });
|
||||
cy.visit('/my-jamtracks');
|
||||
});
|
||||
|
||||
it('should display the My JamTracks page', () => {
|
||||
cy.get('.card-header h5').should('contain', 'My JamTracks');
|
||||
});
|
||||
|
||||
it('should display the search bar', () => {
|
||||
cy.get('input[type="search"]').should('exist');
|
||||
});
|
||||
|
||||
describe('filter', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('GET', /\S+\/jamtracks\/purchased\?page=1\&\S+/, { fixture: 'my_jamtracks_page1' }).as('getMyJamTracks_page1');
|
||||
});
|
||||
|
||||
it('should display the JamTracks', () => {
|
||||
cy.get('input[type="search"]').type('ba');
|
||||
cy.wait('@getMyJamTracks_page1');
|
||||
cy.get('[data-testid=myJamTrackList]').should('contain', 'Back in Black by AC DC');
|
||||
});
|
||||
|
||||
it('clicking on a JamTrack should navigate to the JamTrack page', () => {
|
||||
cy.get('input[type="search"]').type('ba');
|
||||
cy.wait('@getMyJamTracks_page1');
|
||||
cy.get('[data-testid=myJamTrackList] a').first().click();
|
||||
cy.url().should('include', '/jamtrack/1');
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
describe('Top Navigation', () => {
|
||||
const showSubscribeToUpdates = () => {
|
||||
cy.contains('Keep JamKazam Improving').should('exist');
|
||||
cy.contains('Subscribe').should('exist');
|
||||
};
|
||||
|
||||
const showProfileDropdown = () => {
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('exist');
|
||||
cy.contains('Sign Out').should('exist');
|
||||
};
|
||||
|
||||
describe('when user has not logged in', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubUnauthenticate();
|
||||
});
|
||||
|
||||
it('shows homepage', () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
cy.contains('Sign in').should('exist');
|
||||
});
|
||||
|
||||
it('not allowed to protected page', () => {
|
||||
cy.visit('/friends');
|
||||
cy.wait('@getAppFeatures');
|
||||
cy.url().should('include', '/auth/login');
|
||||
cy.contains('Sign in');
|
||||
cy.get('button').should('have.text', 'Sign in');
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user has logged in', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
});
|
||||
|
||||
it('shows user dropdown', () => {
|
||||
showSubscribeToUpdates();
|
||||
showProfileDropdown();
|
||||
});
|
||||
|
||||
it('sign out', () => {
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]')
|
||||
.click();
|
||||
cy.stubUnauthenticate();
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]')
|
||||
.contains('Sign Out')
|
||||
.click();
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist');
|
||||
cy.contains('Sign in');
|
||||
});
|
||||
});
|
||||
|
||||
describe('header notifications', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
cy.intercept('GET', /\S+\/my_notifications/, { fixture: 'notifications' });
|
||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
});
|
||||
|
||||
it('shows notifications', () => {
|
||||
cy.get('[data-testid=notificationDropdown]').should('not.be.visible');
|
||||
cy.get('.bell-icon').click();
|
||||
|
||||
cy.get('[data-testid=notificationDropdown]').should('be.visible');
|
||||
cy.get('[data-testid=notificationDropdown] .list-group-item').should('have.length', 3);
|
||||
cy.get('[data-testid=notificationDropdown]')
|
||||
.contains('View all')
|
||||
.click(); //view all notifications
|
||||
cy.url().should('include', '/notifications');
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('locale switch', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
});
|
||||
|
||||
it('translate', () => {
|
||||
cy.get('.card-header').contains('Home');
|
||||
cy.get('[data-testid=langSwitch]')
|
||||
.contains('ES')
|
||||
.click();
|
||||
cy.get('.card-header').contains('Página de inicio');
|
||||
cy.get('.card-header').should('not.contain', 'Home');
|
||||
cy.get('[data-testid=langSwitch]')
|
||||
.contains('EN')
|
||||
.click();
|
||||
cy.get('.card-header').contains('Home');
|
||||
cy.get('.card-header').should('not.contain', 'Página de inicio');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Side Navigation', () => {
|
||||
describe('backend returns empty set of app features', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
cy.viewport('macbook-13');
|
||||
});
|
||||
|
||||
it('shows all menu items', () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
cy.get('[data-testid=verticalNavigation]').contains('Home');
|
||||
cy.get('[data-testid=verticalNavigation]').contains('Sessions');
|
||||
cy.get('[data-testid=verticalNavigation]').contains('Create Session');
|
||||
cy.get('[data-testid=verticalNavigation]').contains('Friends');
|
||||
});
|
||||
|
||||
it('toggles only one menu on click', () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
cy.get('[data-testid=verticalNavigation]')
|
||||
.contains('Sessions')
|
||||
.click();
|
||||
cy.get('[data-testid=verticalNavigation]')
|
||||
.contains('Create Session')
|
||||
.should('not.visible');
|
||||
cy.get('[data-testid=verticalNavigation]')
|
||||
.contains('Browse Sessions')
|
||||
.should('not.visible');
|
||||
cy.get('[data-testid=verticalNavigation]')
|
||||
.contains('Session History')
|
||||
.should('not.visible');
|
||||
//the Friends menu is not toggled
|
||||
cy.get('[data-testid=verticalNavigation]').contains('Friends');
|
||||
cy.get('[data-testid=verticalNavigation]').contains('My Friends');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('backend returns app features', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
cy.viewport('macbook-13');
|
||||
cy.intercept('GET', /\S+\/app_features/, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
handle: '/sessions',
|
||||
is_enabled: true,
|
||||
feature_type: 'page',
|
||||
env: 'development'
|
||||
},
|
||||
{
|
||||
handle: '/sessions/new',
|
||||
is_enabled: false,
|
||||
feature_type: 'page',
|
||||
env: 'development'
|
||||
},
|
||||
{
|
||||
handle: '/sessions/history',
|
||||
is_enabled: true,
|
||||
feature_type: 'page',
|
||||
env: 'production'
|
||||
},
|
||||
{
|
||||
handle: '/friends',
|
||||
is_enabled: true,
|
||||
feature_type: 'page',
|
||||
env: 'development'
|
||||
},
|
||||
{
|
||||
handle: '/friends/my',
|
||||
is_enabled: true,
|
||||
feature_type: 'page',
|
||||
env: 'development'
|
||||
}
|
||||
]
|
||||
}).as('getAppFeatures');
|
||||
});
|
||||
|
||||
it('shows only enabled menu items', () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
cy.get('[data-testid=verticalNavigation]').contains('Friends');
|
||||
cy.get('[data-testid=verticalNavigation]').contains('Sessions');
|
||||
cy.get('[data-testid=verticalNavigation]').should('not.include.text', 'Create Session')
|
||||
cy.get('[data-testid=verticalNavigation]').should('not.include.text', 'Session History')
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
});
|
||||
|
|
@ -1,463 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeSession from '../../factories/session';
|
||||
import makeFakeUser from '../../factories/user';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
describe('Browse sessions', () => {
|
||||
const currentUser = makeFakeUser();
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate({ id: currentUser.id });
|
||||
});
|
||||
|
||||
describe('when there are no active sessions', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, {
|
||||
body: []
|
||||
});
|
||||
cy.visit('/sessions');
|
||||
});
|
||||
|
||||
it('alerts when there is no records', () => {
|
||||
cy.contains('There are no public, open sessions currently available for you to join');
|
||||
cy.contains('create a session').click();
|
||||
cy.url().should('include', '/sessions/new');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there are active sessions', () => {
|
||||
describe('in desktop', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('macbook-15');
|
||||
});
|
||||
|
||||
it('lists the sessions', () => {
|
||||
const session = makeFakeSession({
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').should('have.length', 1);
|
||||
});
|
||||
|
||||
describe('session description', () => {
|
||||
it('when user has provided a description', () => {
|
||||
const session = makeFakeSession({
|
||||
description: 'custom description',
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('custom description');
|
||||
});
|
||||
|
||||
it('when user has not provided a description and session is public', () => {
|
||||
const session = makeFakeSession({
|
||||
description: null,
|
||||
musician_access: true,
|
||||
approval_required: false,
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('Public, open session. Feel free to join!');
|
||||
});
|
||||
|
||||
it('when user has not provided a description and session is private and requires approval to join', () => {
|
||||
const session = makeFakeSession({
|
||||
description: null,
|
||||
musician_access: true,
|
||||
approval_required: true,
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains(
|
||||
'Private session. Click the enter button in the right column to request to join'
|
||||
);
|
||||
});
|
||||
|
||||
it('when user has not provided a description and session is RSVP', () => {
|
||||
const session = makeFakeSession({
|
||||
description: null,
|
||||
musician_access: false,
|
||||
approval_required: false,
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('Only RSVP musicians may join');
|
||||
});
|
||||
});
|
||||
|
||||
describe('invitation', () => {
|
||||
it('shows invite detail if the user has been invited', () => {
|
||||
const session = makeFakeSession({
|
||||
invitations: [
|
||||
{
|
||||
sender_id: '1',
|
||||
receiver_id: currentUser.id
|
||||
}
|
||||
],
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('YOU WERE INVITED TO THIS SESSION');
|
||||
});
|
||||
});
|
||||
|
||||
describe('friend info', () => {
|
||||
it('shows if there is a friend in session', () => {
|
||||
const session = makeFakeSession({
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
is_friend: true,
|
||||
name: faker.person.fullName()
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
//console.log('_DEBUG_ session', session);
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('YOU HAVE A FRIEND IN THIS SESSION');
|
||||
});
|
||||
});
|
||||
|
||||
describe('participants', () => {
|
||||
it('shows the participants', () => {
|
||||
const session = makeFakeSession({
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('John Doe');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('Ray Charles');
|
||||
});
|
||||
});
|
||||
|
||||
describe('instruments', () => {
|
||||
it('shows the instruments', () => {
|
||||
const session = makeFakeSession({
|
||||
participants: [
|
||||
{
|
||||
id: 'p1',
|
||||
user: {
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Electric Guitar',
|
||||
instrument_id: 'electric_guitar'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Drums',
|
||||
instrument_id: 'drums'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'p2',
|
||||
user: {
|
||||
name: 'Ray Charles'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '2',
|
||||
instrument: 'Bass Guitar',
|
||||
instrument_id: 'bass_guitar'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||
.find(`[data-testid=Participantp1Tracks]`).trigger('mouseover')
|
||||
//cy.contains('Electric Guitar');
|
||||
// cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||
// .find(`[data-testid=Participantp1Tracks]`)
|
||||
// .contains('Drums');
|
||||
// cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||
// .find(`[data-testid=Participantp2Tracks]`)
|
||||
// .contains('Bass');
|
||||
});
|
||||
});
|
||||
|
||||
describe('click join button - on a private session', () => {
|
||||
it('shows toast message', () => {
|
||||
const session = makeFakeSession({
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
id: '1',
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
musician_access: true,
|
||||
approval_required: true
|
||||
});
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.intercept('GET', /\S+\/api\/users\/\S+\/latencies\?\S+/, { users: [{
|
||||
user_id: currentUser.id,
|
||||
first_name:"John",
|
||||
last_name:"Doe",
|
||||
audio_latency:5,
|
||||
audio_latency_unknown:false,
|
||||
}]});
|
||||
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||
.find('[data-testid=joinBtn]')
|
||||
.click();
|
||||
cy.contains('You have requested to join this private session.');
|
||||
// cy.get('[data-testid=native-app-unavailable]').contains('Cancel').click();
|
||||
});
|
||||
});
|
||||
|
||||
describe('click join button - on a public session', () => {
|
||||
it('opens native client', () => {
|
||||
const session = makeFakeSession({
|
||||
participants: [
|
||||
{
|
||||
user: {
|
||||
id: '1',
|
||||
name: 'John Doe'
|
||||
},
|
||||
tracks: [
|
||||
{
|
||||
id: '1',
|
||||
instrument: 'Guitar'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
musician_access: true,
|
||||
approval_required: false
|
||||
});
|
||||
const newUrl = `jamkazam://url=http://www.jamkazam.local:3000/client#/findSession/custom~yes%7CjoinSessionId~${
|
||||
session.id
|
||||
}`;
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.intercept('GET', /\S+\/api\/users\/\S+\/latencies\?\S+/, { users: [{
|
||||
user_id: currentUser.id,
|
||||
first_name:"John",
|
||||
last_name:"Doe",
|
||||
audio_latency:5,
|
||||
audio_latency_unknown:false,
|
||||
}]});
|
||||
cy.visit('/sessions').then(win => {
|
||||
cy.stub(win, 'open').as('windowOpen');
|
||||
});
|
||||
// cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||
// .find('[data-testid=joinBtn]')
|
||||
// .click();
|
||||
//cy.get('@windowOpen').should('have.been.calledWith', newUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('in mobile', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport('iphone-6');
|
||||
});
|
||||
|
||||
describe('pagination', () => {
|
||||
it('shows the next page of sessions', () => {
|
||||
const sessions = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
sessions.push(makeFakeSession({ id: faker.string.uuid() }));
|
||||
}
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, sessions);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsSwiper] .swiper-button-prev').should('have.class', 'swiper-button-disabled');
|
||||
for (let i = 0; i < 4; i++) {
|
||||
// 4 because the first one is already visible
|
||||
cy.get('[data-testid=sessionsSwiper] .swiper-button-next').click();
|
||||
cy.wait(500);
|
||||
}
|
||||
cy.get('[data-testid=sessionsSwiper] .swiper-button-next').should('have.class', 'swiper-button-disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import useNativeAppCheck from '../../../src/hooks/useNativeAppCheck';
|
||||
|
||||
describe('Create new session', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate({ id: '6' });
|
||||
cy.intercept('GET', /\S+\/users\/\d+\/friends/, { fixture: 'friends' }).as('friends');
|
||||
|
||||
});
|
||||
|
||||
it("adds invitees - using autocomplete list click", () => {
|
||||
cy.visit('/sessions/new');
|
||||
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
||||
cy.get('[data-testid=autocomplete-list] li').should('have.length', 2)
|
||||
cy.get('[data-testid=autocomplete-list] li:first').click()
|
||||
cy.get('[data-testid=selected-invitees]').children().first().contains('David Wilson')
|
||||
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
||||
cy.get('[data-testid=autocomplete-list] li').should('have.length', 1)
|
||||
cy.get('[data-testid=autocomplete-list] li').should('not.contain', 'David Wilson')
|
||||
});
|
||||
|
||||
//skipping this test for now. according to the html specification, when there is a single text field in a form
|
||||
//the behaviour is to submit the form on hitting the enter key. need to figureout a way to prevent this.
|
||||
//https://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2
|
||||
it.skip("adds invitees using autocomplete enter", () => {
|
||||
cy.visit('/sessions/new');
|
||||
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
||||
cy.get('[data-testid=autocomplete-list] li').should('have.length', 2)
|
||||
cy.get('[data-testid=autocomplete-text]').type('{enter}')
|
||||
cy.get('[data-testid=selected-invitees]').children().first().contains('David Wilson')
|
||||
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
||||
cy.get('[data-testid=autocomplete-list] li').should('have.length', 1)
|
||||
cy.get('[data-testid=autocomplete-list] li').should('not.contain', 'David Wilson')
|
||||
});
|
||||
|
||||
it("removes invitees", () => {
|
||||
cy.visit('/sessions/new');
|
||||
cy.get('[data-testid=autocomplete-text]').type('Seth')
|
||||
cy.get('[data-testid=autocomplete-list] li').should('have.length', 1)
|
||||
cy.get('[data-testid=autocomplete-list] li:first').click()
|
||||
cy.get('[data-testid=selected-invitees]').children().first().contains('Seth Call')
|
||||
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
||||
cy.get('[data-testid=autocomplete-list] li').should('have.length', 2)
|
||||
cy.get('[data-testid=autocomplete-list] li:first').click()
|
||||
cy.get('[data-testid=selected-invitees]').children().first().find('a').click()
|
||||
cy.get('[data-testid=selected-invitees]').children().should('have.length', 1)
|
||||
cy.get('[data-testid=selected-invitees]').children().first().find('a').click()
|
||||
cy.get('[data-testid=selected-invitees]').should('not.exist')
|
||||
});
|
||||
|
||||
it("choose friends as invitees", ()=> {
|
||||
cy.visit('/sessions/new');
|
||||
cy.get('[data-testid=btn-choose-friends]').click();
|
||||
cy.get('[data-testid=modal-choose-friends]').should('be.visible').contains('Invite Friends to Session')
|
||||
cy.get('[data-testid=modal-choose-friends]').find('[type="checkbox"]').first().click()
|
||||
cy.get('[data-testid=modal-choose-friends]').contains('Add Friends').click()
|
||||
cy.get('[data-testid=selected-invitees]').children().first().contains('Seth Call')
|
||||
cy.get('[data-testid=btn-choose-friends]').click();
|
||||
cy.get('[data-testid=modal-choose-friends]').should('not.contain', 'Seth Call')
|
||||
})
|
||||
|
||||
it.only("prefill form using saved data in localStorage", () => {
|
||||
cy.visit('/sessions/new');
|
||||
cy.get('[data-testid=session-privacy]').select("2")
|
||||
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
||||
cy.get('[data-testid=autocomplete-list] li:first').click()
|
||||
cy.get('[data-testid=session-description]').type("My test session")
|
||||
cy.get('[data-testid=btn-create-session]').click();
|
||||
cy.reload() //refresh browser
|
||||
cy.get('[data-testid=session-privacy]').should('have.value', "2")
|
||||
cy.get('[data-testid=selected-invitees]').children().first().contains('David Wilson')
|
||||
cy.get('[data-testid=session-description]').contains('My test session')
|
||||
})
|
||||
|
||||
it("submits form", () => {
|
||||
const newUrl = `jamkazam://url=http://www.jamkazam.local:3000/client#/createSession/custom~yes%7Cprivacy~2%7Cdescription~test%7CinviteeIds~1`;
|
||||
cy.visit('/sessions/new').then((win) => {
|
||||
cy.stub(win, 'open').as('windowOpen');
|
||||
});
|
||||
cy.get('[data-testid=session-privacy]').select("2")
|
||||
cy.get('[data-testid=autocomplete-text]').type('Seth')
|
||||
cy.get('[data-testid=autocomplete-list] li:first').click()
|
||||
cy.get('[data-testid=session-description]').type("test")
|
||||
cy.get('[data-testid=btn-create-session]').click();
|
||||
cy.get('@windowOpen').should('have.been.calledWith', newUrl);
|
||||
cy.get('[data-testid=btn-create-session]').should('be.disabled')
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue