Compare commits
No commits in common. "develop" and "develop_temp" have entirely different histories.
develop
...
develop_te
|
|
@ -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!"
|
|
||||||
|
|
@ -11,4 +11,4 @@ working.png
|
||||||
ruby/.rails5-gems
|
ruby/.rails5-gems
|
||||||
web/.rails5-gems
|
web/.rails5-gems
|
||||||
websocket-gateway/.rails5-gems
|
websocket-gateway/.rails5-gems
|
||||||
.pg_data/
|
.pg_data/
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
|
||||||
|
|
||||||
menu :label => 'Quarterly Reports', :parent => 'Affiliates'
|
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.batch_actions = false
|
||||||
config.clear_action_items!
|
config.clear_action_items!
|
||||||
config.filters = true
|
config.filters = true
|
||||||
|
|
@ -14,32 +14,18 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
|
||||||
filter :quarter
|
filter :quarter
|
||||||
filter :closed
|
filter :closed
|
||||||
filter :paid
|
filter :paid
|
||||||
filter :jamtracks_sold
|
|
||||||
filter :subscriptions_count
|
|
||||||
filter :due_amount_in_cents
|
|
||||||
|
|
||||||
form :partial => 'form'
|
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
|
index do
|
||||||
|
|
||||||
# default_actions # use this for all view/edit/delete links
|
# default_actions # use this for all view/edit/delete links
|
||||||
|
|
||||||
column 'Year' do |oo| oo.year end
|
column 'Year' do |oo| oo.year end
|
||||||
column 'Quarter' do |oo| oo.quarter 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 '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 "Due (\u00A2)" do |oo| oo.due_amount_in_cents end
|
||||||
column "Sub ($)" do |oo| sprintf("$%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f) end
|
column 'JamTracks Sold' do |oo| oo.jamtracks_sold 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 'Paid' do |oo| oo.paid end
|
column 'Paid' do |oo| oo.paid end
|
||||||
column 'Closed' 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
|
# default_actions # use this for all view/edit/delete links
|
||||||
|
|
||||||
column 'Day' do |oo| oo.day end
|
column 'Day' do |oo| oo.day 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 '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 'Signups' do |oo| oo.signups end
|
column 'Signups' do |oo| oo.signups end
|
||||||
column 'Visits' do |oo| oo.visits end
|
column 'Visits' do |oo| oo.visits end
|
||||||
|
|
||||||
|
|
@ -33,16 +31,6 @@ ActiveAdmin.register JamRuby::AffiliateTrafficTotal, :as => 'Affiliate Daily Sta
|
||||||
|
|
||||||
|
|
||||||
controller do
|
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
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -8,32 +8,27 @@ ActiveAdmin.register JamRuby::User, :as => 'Referrals' do
|
||||||
config.filters = true
|
config.filters = true
|
||||||
|
|
||||||
filter :affiliate_referral
|
filter :affiliate_referral
|
||||||
filter :email
|
|
||||||
|
|
||||||
## scope("Has Signups", default: true) { |scope| scope.where('visits != 0 or signups != 0').order('day desc') }
|
|
||||||
|
|
||||||
index do
|
index do
|
||||||
column 'User' do |oo| link_to(oo.name, oo.admin_url, {:title => oo.name}) end
|
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 'Created' do |oo| oo.created_at end
|
||||||
column 'Partner ID' do |oo| oo.affiliate_referral.id end
|
column 'Partner' do |oo| oo.affiliate_referral.display_name 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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
controller do
|
controller do
|
||||||
|
|
||||||
def scoped_collection
|
def scoped_collection
|
||||||
rel = end_of_association_chain
|
rel = end_of_association_chain
|
||||||
.includes([:affiliate_referral])
|
.includes([:affiliate_referral])
|
||||||
.order('created_at DESC')
|
.order('created_at DESC')
|
||||||
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
||||||
qq = ['affiliate_referral_id = ?', ref_id]
|
qq = ['affiliate_referral_id = ?', ref_id]
|
||||||
else
|
else
|
||||||
qq = ['affiliate_referral_id IS NOT NULL']
|
qq = ['affiliate_referral_id IS NOT NULL']
|
||||||
|
end
|
||||||
|
@users ||= rel.where(qq)
|
||||||
end
|
end
|
||||||
@users ||= rel.where(qq)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -5,35 +5,19 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
||||||
config.sort_order = 'referral_user_count DESC'
|
config.sort_order = 'referral_user_count DESC'
|
||||||
config.batch_actions = false
|
config.batch_actions = false
|
||||||
# config.clear_action_items!
|
# config.clear_action_items!
|
||||||
config.filters = true
|
config.filters = false
|
||||||
config.per_page = 100
|
config.per_page = 50
|
||||||
config.paginate = true
|
config.paginate = true
|
||||||
|
|
||||||
#form :partial => 'form'
|
#form :partial => 'form'
|
||||||
|
|
||||||
|
scope("Active", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
|
||||||
#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("Unpaid") { |partner| partner.unpaid }
|
scope("Unpaid") { |partner| partner.unpaid }
|
||||||
|
|
||||||
controller do
|
controller do
|
||||||
helper 'active_admin/subscription'
|
helper 'active_admin/subscription'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
form do |f|
|
form do |f|
|
||||||
f.inputs 'Fields' do
|
f.inputs 'Fields' do
|
||||||
f.input(:partner_name, :input_html => { :maxlength => 128 })
|
f.input(:partner_name, :input_html => { :maxlength => 128 })
|
||||||
|
|
@ -61,47 +45,14 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
||||||
column 'Code' do |oo|
|
column 'Code' do |oo|
|
||||||
oo.id
|
oo.id
|
||||||
end
|
end
|
||||||
column 'Signups' do |oo|
|
column 'Referral Count' do |oo|
|
||||||
oo.referral_user_count
|
oo.referral_user_count
|
||||||
end
|
end
|
||||||
column 'JamTracks' do |oo|
|
column 'Earnings' do |oo|
|
||||||
oo.jamtracks_sold
|
sprintf("$%.2f", oo.cumulative_earnings_in_dollars)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
column 'Amount Owed' do |oo|
|
column 'Amount Owed' do |oo|
|
||||||
div do
|
sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
column 'Pay Actions' do |oo|
|
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
|
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 :address
|
||||||
row :tax_identifier
|
row :tax_identifier
|
||||||
row :paypal_id
|
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
|
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
|
|
||||||
|
|
@ -640,12 +640,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
||||||
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, extra_data: [:last_jam_addr]
|
||||||
|
|
||||||
def get_autocomplete_items(parameters)
|
def get_autocomplete_items(parameters)
|
||||||
term = parameters[:term]
|
User.select("email, first_name, last_name, id, last_jam_addr").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{parameters[:term]}%", "%#{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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,6 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
||||||
|
|
||||||
filter :jam_track
|
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
|
index do
|
||||||
actions
|
actions
|
||||||
|
|
||||||
|
|
@ -55,14 +47,9 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
||||||
|
|
||||||
form do |f|
|
form do |f|
|
||||||
f.inputs 'New Jam Track Right' do
|
f.inputs 'New Jam Track Right' do
|
||||||
#f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
|
f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
|
||||||
f.input :jam_track_id_val, :required=>true, :as => :hidden
|
f.input :user, :required=>true, collection: User.all, include_blank: false
|
||||||
|
f.input :can_download, :required => true, as: :boolean
|
||||||
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' }
|
|
||||||
end
|
end
|
||||||
f.actions
|
f.actions
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
||||||
|
|
||||||
collection_action :autocomplete_jam_track_name, :method => :get
|
|
||||||
|
|
||||||
menu :label => 'JamTracks', :parent => 'JamTracks'
|
menu :label => 'JamTracks', :parent => 'JamTracks'
|
||||||
|
|
||||||
config.sort_order = 'name_asc'
|
config.sort_order = 'name_asc'
|
||||||
|
|
@ -21,19 +19,6 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
||||||
|
|
||||||
form :partial => 'form'
|
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
|
index do
|
||||||
|
|
||||||
# actions # use this for all view/edit/delete links
|
# 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(first_subscribed_at) 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
|
||||||
|
|
@ -6,18 +6,15 @@ ActiveAdmin.register JamRuby::User, :as => 'UserSource' do
|
||||||
config.batch_actions = false
|
config.batch_actions = false
|
||||||
config.clear_action_items!
|
config.clear_action_items!
|
||||||
config.filters = false
|
config.filters = false
|
||||||
config.per_page = 250
|
|
||||||
|
|
||||||
scope("Paid", default: true) { |scope| scope.unscoped.where(:origin_utm_medium => 'cpc').order('created_at desc') }
|
scope("Most Recent First", default: true) { |scope| scope.unscoped.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') }
|
|
||||||
|
|
||||||
index do
|
index do
|
||||||
column "Email" do |user|
|
column "Email" do |user|
|
||||||
user.email
|
user.email
|
||||||
end
|
end
|
||||||
column "Signup (CST)" do |user|
|
column "Bought TestDrive" do |user|
|
||||||
user.created_at.in_time_zone("Central Time (US & Canada)")
|
!user.most_recent_test_drive_purchase.nil? ? "Yes" : "No"
|
||||||
end
|
end
|
||||||
column "UTM Source" do |user|
|
column "UTM Source" do |user|
|
||||||
user.origin_utm_source
|
user.origin_utm_source
|
||||||
|
|
@ -28,23 +25,8 @@ ActiveAdmin.register JamRuby::User, :as => 'UserSource' do
|
||||||
column "UTM Campaign" do |user|
|
column "UTM Campaign" do |user|
|
||||||
user.origin_utm_campaign
|
user.origin_utm_campaign
|
||||||
end
|
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|
|
column "Referrer" do |user|
|
||||||
user.origin_referrer
|
user.origin_referrer
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -7,38 +7,6 @@ function intToIP(int) {
|
||||||
return part4 + "." + part3 + "." + part2 + "." + part1;
|
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(){
|
function handleUserLatencyForm(){
|
||||||
var $userLatenciesForm = $('form#user_latencies_form');
|
var $userLatenciesForm = $('form#user_latencies_form');
|
||||||
var $latenciesMyUser = $userLatenciesForm.find('#latencies_my_user');
|
var $latenciesMyUser = $userLatenciesForm.find('#latencies_my_user');
|
||||||
|
|
@ -106,5 +74,4 @@ function handleLatencyRecommendationForm(){
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
handleUserLatencyForm();
|
handleUserLatencyForm();
|
||||||
handleLatencyRecommendationForm();
|
handleLatencyRecommendationForm();
|
||||||
handleJamTrackRightsForm();
|
|
||||||
});
|
});
|
||||||
|
|
@ -2,97 +2,55 @@ class ArsesController < ApplicationController
|
||||||
|
|
||||||
respond_to :json
|
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
|
# create or update a client_artifact row
|
||||||
def get_or_create
|
def get_or_create
|
||||||
begin
|
name = params[:name]
|
||||||
name = params[:name]
|
provider = params[:provider]
|
||||||
provider = params[:provider]
|
active = params[:active]
|
||||||
active = params[:active]
|
ip = params[:ip]
|
||||||
beta = params.has_key?(:beta) ? params[:beta] : true
|
username = params[:username]
|
||||||
ip = params[:ip]
|
password = params[:password]
|
||||||
username = params[:username]
|
topology = params[:topology]
|
||||||
password = params[:password]
|
ars_id = params[:ars_id]
|
||||||
topology = params[:topology]
|
puts "TOPOLOGY #{topology}"
|
||||||
ars_id = params[:ars_id]
|
|
||||||
|
|
||||||
# Explicit field-based lookups
|
if ars_id
|
||||||
ars = nil
|
ars = Ars.find_by_id_int(ars_id)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
if ars.nil?
|
||||||
|
ars = Ars.new
|
||||||
|
ars.name = name
|
||||||
|
ars.id_int = ars_id if !ars_id.nil?
|
||||||
|
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?
|
||||||
|
if ars_id.nil?
|
||||||
|
ars.reload
|
||||||
|
ars_id = ars.id_int
|
||||||
|
end
|
||||||
|
|
||||||
|
@ars = Ars.find_by_id_int(ars_id)
|
||||||
|
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
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -112,19 +112,6 @@ class Cohort < ActiveRecord::Base
|
||||||
def self.cohort_users(cohort)
|
def self.cohort_users(cohort)
|
||||||
User.where(created_at: cohort.group_start..cohort.group_end)
|
User.where(created_at: cohort.group_start..cohort.group_end)
|
||||||
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)
|
def _played_online_subquery(constraint)
|
||||||
where = if constraint.is_a?(Range)
|
where = if constraint.is_a?(Range)
|
||||||
|
|
|
||||||
|
|
@ -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.email_smtp_starttls_auto = true
|
||||||
|
|
||||||
config.verify_email_enabled = false
|
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_id = ENV['FACEBOOK_APP_ID'] || '468555793186398'
|
||||||
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'
|
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
# add a custom validation
|
||||||
|
|
||||||
|
|
||||||
def autocomplete_display_name
|
|
||||||
"#{original_artist} - #{name}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,6 @@ JamAdmin::Application.routes.draw do
|
||||||
post :user_latencies, on: :collection
|
post :user_latencies, on: :collection
|
||||||
post :user_latency_recommendation, on: :collection
|
post :user_latency_recommendation, on: :collection
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :jam_tracks do
|
|
||||||
get :autocomplete_jam_track_name, :on => :collection
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :admin do
|
namespace :admin do
|
||||||
|
|
@ -44,8 +40,6 @@ JamAdmin::Application.routes.draw do
|
||||||
match '/api/jam_tracks/released' => 'jam_track#dump_released', :via => :get, as: 'released_jamtracks_csv'
|
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/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"
|
mount Resque::Server.new, :at => "/resque"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
# trigger build
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
image: node:14.21.3
|
image: node:14.17.1
|
||||||
|
|
||||||
pipelines:
|
pipelines:
|
||||||
branches:
|
branches:
|
||||||
|
|
@ -6,93 +6,33 @@ pipelines:
|
||||||
- step:
|
- step:
|
||||||
name: Build Staging
|
name: Build Staging
|
||||||
script:
|
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
|
- 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
|
- npm install
|
||||||
|
- CI=false REACT_APP_ORIGIN=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 npm run build
|
||||||
artifacts:
|
artifacts:
|
||||||
- jam-ui/build/**
|
- jam-ui/build/**
|
||||||
- step:
|
- step:
|
||||||
name: Deploy to staging - SPA
|
name: Deploy to staging
|
||||||
|
deployment: staging
|
||||||
script:
|
script:
|
||||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
- pipe: atlassian/aws-s3-deploy:1.1.0
|
||||||
variables:
|
variables:
|
||||||
S3_BUCKET: "jamkazam-ui/stg"
|
S3_BUCKET: "jamkazam-ui/stg"
|
||||||
LOCAL_PATH: "jam-ui/build"
|
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:
|
- step:
|
||||||
name: Build Production
|
name: Build Production
|
||||||
script:
|
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
|
- 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
|
- npm install
|
||||||
|
- CI=false REACT_APP_ORIGIN=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 npm run build
|
||||||
artifacts:
|
artifacts:
|
||||||
- jam-ui/build/**
|
- jam-ui/build/**
|
||||||
|
|
||||||
- step:
|
- step:
|
||||||
name: Deploy to production - SPA
|
name: Deploy to production
|
||||||
|
deployment: production
|
||||||
script:
|
script:
|
||||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
- pipe: atlassian/aws-s3-deploy:1.1.0
|
||||||
variables:
|
variables:
|
||||||
S3_BUCKET: "jamkazam-ui/prd"
|
S3_BUCKET: "jamkazam-ui/prd"
|
||||||
LOCAL_PATH: "jam-ui/build"
|
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,16 +1,7 @@
|
||||||
HOST=beta.jamkazam.local
|
HOST=beta.jamkazam.local
|
||||||
PORT=4000
|
PORT=4000
|
||||||
REACT_APP_ORIGIN=jamkazam.local
|
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_CLIENT_BASE_URL=http://www.jamkazam.local:3000
|
||||||
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
||||||
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
||||||
REACT_APP_BITBUCKET_COMMIT=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 +1,7 @@
|
||||||
HOST=beta.jamkazam.local
|
HOST=beta.jamkazam.local
|
||||||
PORT=4000
|
PORT=4000
|
||||||
REACT_APP_ORIGIN=jamkazam.local
|
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_CLIENT_BASE_URL=http://www.jamkazam.local:3000
|
||||||
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
||||||
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
||||||
REACT_APP_BITBUCKET_COMMIT=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 +1,5 @@
|
||||||
HOST=beta.jamkazam.com
|
HOST=beta.jamkazam.com
|
||||||
PORT=4000
|
PORT=4000
|
||||||
REACT_APP_ORIGIN=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_CLIENT_BASE_URL=https://www.jamkazam.com
|
||||||
REACT_APP_API_BASE_URL=https://www.jamkazam.com/api
|
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 +1,5 @@
|
||||||
HOST=beta.staging.jamkazam.com
|
HOST=beta.staging.jamkazam.com
|
||||||
PORT=4000
|
PORT=4000
|
||||||
REACT_APP_ORIGIN=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_CLIENT_BASE_URL=https://staging.jamkazam.com
|
||||||
REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api
|
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
|
|
||||||
|
|
@ -3,6 +3,6 @@
|
||||||
"plugins": ["prettier"],
|
"plugins": ["prettier"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"react/no-unescaped-entities": 0
|
"react/no-unescaped-entities": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,4 @@ yarn-error.log*
|
||||||
/test-results
|
/test-results
|
||||||
|
|
||||||
/cypress/videos/
|
/cypress/videos/
|
||||||
/cypress/screenshots/
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
|
||||||
/public/backing-tracks
|
|
||||||
/public/js
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
v14.21.3
|
v14.17.1
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,5 @@
|
||||||
# JamKazam new react frontend UI/UX
|
# 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
|
## 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)
|
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)
|
||||||
|
|
@ -38,19 +29,3 @@ 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.
|
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,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.')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -30,9 +30,9 @@ function submitLogin(){
|
||||||
describe('Unauthenticated users redirect to login page', () => {
|
describe('Unauthenticated users redirect to login page', () => {
|
||||||
it('redirects to login page', () => {
|
it('redirects to login page', () => {
|
||||||
cy.clearCookie('remeber_token')
|
cy.clearCookie('remeber_token')
|
||||||
cy.visit('/')
|
cy.visit('/friends')
|
||||||
cy.url().should('include', '/auth/login')
|
cy.url().should('include', '/authentication/basic/login')
|
||||||
cy.contains('Sign In')
|
cy.contains('Sign in')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ describe('Login page', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('validate login form', () => {
|
it('validate login form', () => {
|
||||||
cy.visit('/auth/login')
|
cy.visit('/authentication/basic/login')
|
||||||
cy.reload()
|
cy.reload()
|
||||||
cy.get('[data-testid=submit]').should('be.disabled')
|
cy.get('[data-testid=submit]').should('be.disabled')
|
||||||
cy.get('[data-testid=email]').type('invalid-email-format@example')
|
cy.get('[data-testid=email]').type('invalid-email-format@example')
|
||||||
|
|
@ -54,7 +54,7 @@ describe('Login page', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('submit login form with invalid credentials', () => {
|
it('submit login form with invalid credentials', () => {
|
||||||
cy.visit('/auth/login')
|
cy.visit('/authentication/basic/login')
|
||||||
cy.reload()
|
cy.reload()
|
||||||
cy.get('[data-testid=email]').type('peter@example.com')
|
cy.get('[data-testid=email]').type('peter@example.com')
|
||||||
cy.get('[data-testid=password]').type('wrong')
|
cy.get('[data-testid=password]').type('wrong')
|
||||||
|
|
@ -63,7 +63,7 @@ describe('Login page', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('submits login form', () => {
|
it('submits login form', () => {
|
||||||
cy.visit('/auth/login')
|
cy.visit('/authentication/basic/login')
|
||||||
submitLogin()
|
submitLogin()
|
||||||
cy.url().should('eq', Cypress.config().baseUrl + '/') // tests won't fail in case the port changes
|
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('Signed in as peter@example.com')
|
||||||
|
|
@ -73,7 +73,7 @@ describe('Login page', () => {
|
||||||
|
|
||||||
it('redirect to requested page', () => {
|
it('redirect to requested page', () => {
|
||||||
cy.visit('/friends')
|
cy.visit('/friends')
|
||||||
cy.url().should('include', '/auth/login')
|
cy.url().should('include', '/authentication/basic/login')
|
||||||
cy.reload()
|
cy.reload()
|
||||||
submitLogin()
|
submitLogin()
|
||||||
cy.url().should('eq', Cypress.config().baseUrl + '/friends')
|
cy.url().should('eq', Cypress.config().baseUrl + '/friends')
|
||||||
|
|
@ -81,13 +81,4 @@ describe('Login page', () => {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
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')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,16 @@
|
||||||
|
|
||||||
const showSidePanelContent = () => {
|
const showSidePanelContent = () => {
|
||||||
cy.get('[data-testid=profileSidePanel] h4').should('have.text', 'Test User1');
|
cy.get('[data-testid=profileSidePanel] h4').should('have.text', 'Test User1');
|
||||||
cy.get('[data-testid=profileSidePanel] .modal-body').first().within(() => {
|
cy.get('[data-testid=profileSidePanel] .modal-body p').first().within(() => {
|
||||||
cy.contains('Location: Denver, CO, US')
|
cy.contains('Location: Denver, CO, US')
|
||||||
.and('contain', 'Skill Level: Professional')
|
.and('contain', 'Skill Level: Professional')
|
||||||
.and('contain', 'Joined JamKazam: 08-26-2021')
|
.and('contain', 'Joined JamKazam: 08-26-2021')
|
||||||
.and('contain', 'Last Active:')
|
.and('contain', 'Last Active:')
|
||||||
.and('contain', 'Latency To Me:');
|
.and('contain', 'Latency To Me:');
|
||||||
cy.get('.latency-badge').contains('UNKNOWN');
|
cy.get('.latency-badge').contains('UNKNOWN');
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-testid=profileSidePanel] .modal-body').first().within(() => {
|
||||||
cy.get('[data-testid=biography]').contains('Biography of Test User1');
|
cy.get('[data-testid=biography]').contains('Biography of Test User1');
|
||||||
|
|
||||||
//instruments
|
//instruments
|
||||||
|
|
@ -23,14 +25,17 @@ const showSidePanelContent = () => {
|
||||||
cy.get('[data-testid=bands]').contains('The Band');
|
cy.get('[data-testid=bands]').contains('The Band');
|
||||||
|
|
||||||
//performance_samples
|
//performance_samples
|
||||||
cy.get('[data-testid=performance_samples]').contains('Test Recording1')//.should('have.attr', 'href').and('eq', 'https://www.jamkazam.com/test-recording1');
|
//cy.get('[data-testid=performance_samples]').contains('The Band')
|
||||||
|
|
||||||
//online presence
|
//online presence
|
||||||
|
cy.get('[data-testid=online_presences]').contains('Soundcloud').should('have.attr', 'href').and('eq', 'https://www.soundcloud.com/testuser');
|
||||||
|
cy.get('[data-testid=online_presences]').contains('Reverbnation').should('have.attr', 'href').and('eq', 'https://www.reverbnation.com/testuser');
|
||||||
|
cy.get('[data-testid=online_presences]').contains('Bandcamp').should('have.attr', 'href').and('eq', 'https://testuser.bandcamp.com');
|
||||||
|
cy.get('[data-testid=online_presences]').contains('Fandalism').should('have.attr', 'href').and('eq', 'https://www.fandalism.com/testuser');
|
||||||
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('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('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');
|
cy.get('[data-testid=online_presences]').contains('Twitter').should('have.attr', 'href').and('eq', 'https://www.twitter.com/testuser');
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeSidePanel = () => {
|
const closeSidePanel = () => {
|
||||||
|
|
@ -45,8 +50,7 @@ describe('Friends page without data', () => {
|
||||||
}).as("getPeople_empty");
|
}).as("getPeople_empty");
|
||||||
});
|
});
|
||||||
|
|
||||||
//from_location checkbox is hidden for now. so we skip this test for now
|
it('from_location is unchecked', () => {
|
||||||
it.skip('from_location is unchecked', () => {
|
|
||||||
cy.visit('/friends');
|
cy.visit('/friends');
|
||||||
|
|
||||||
//default api call with from_location parameter turned off
|
//default api call with from_location parameter turned off
|
||||||
|
|
@ -99,11 +103,7 @@ describe('Friends page with data', () => {
|
||||||
cy.intercept('POST', /\S+\/filter\?offset=0/, { fixture: 'people_page1' }).as('getPeople_page1');
|
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=10/, { fixture: 'people_page2' }).as('getPeople_page2');
|
||||||
cy.intercept('POST', /\S+\/filter\?offset=20/, { fixture: 'people_page3' }).as('getPeople_page3');
|
cy.intercept('POST', /\S+\/filter\?offset=20/, { fixture: 'people_page3' }).as('getPeople_page3');
|
||||||
cy.intercept('GET', /\S+\/profile/, { fixture: 'person' });
|
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||||
cy.intercept('GET', /\S+\/my_notifications\S+/, {
|
|
||||||
statusCode: 200,
|
|
||||||
body: []
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('listing users', () => {
|
describe('listing users', () => {
|
||||||
|
|
@ -121,6 +121,7 @@ describe('Friends page with data', () => {
|
||||||
cy.wait('@getPeople_page2')
|
cy.wait('@getPeople_page2')
|
||||||
cy.get('[data-testid=paginate-next-page]').click();
|
cy.get('[data-testid=paginate-next-page]').click();
|
||||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 20);
|
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=paginate-next-page]').click();
|
||||||
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 30);
|
cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 30);
|
||||||
cy.get('[data-testid=paginate-next-page]').should('not.exist');
|
cy.get('[data-testid=paginate-next-page]').should('not.exist');
|
||||||
|
|
@ -182,7 +183,7 @@ describe('Friends page with data', () => {
|
||||||
.first()
|
.first()
|
||||||
.find('[data-testid=instrumentList]')
|
.find('[data-testid=instrumentList]')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('[data-testid=instrument]').should('have.length', 4); //show only 4 instruments plus more link
|
cy.get('div').should('have.length', 4); //show only 4 instruments plus more link
|
||||||
cy.contains('Acoustic Guitar: Expert');
|
cy.contains('Acoustic Guitar: Expert');
|
||||||
cy.contains('Keyboard: Expert');
|
cy.contains('Keyboard: Expert');
|
||||||
cy.contains('Ukulele: Expert');
|
cy.contains('Ukulele: Expert');
|
||||||
|
|
@ -305,7 +306,7 @@ describe('Friends page with data', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('remove friend', () => {
|
it('remove friend', () => {
|
||||||
cy.intercept('GET', /\S+\/profile/, { fixture: 'friend' });
|
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'friend' });
|
||||||
cy.intercept('DELETE', /\S+\/friends\S+/, { statusCode: 204, body: { ok: true } });
|
cy.intercept('DELETE', /\S+\/friends\S+/, { statusCode: 204, body: { ok: true } });
|
||||||
|
|
||||||
cy.visit('/friends');
|
cy.visit('/friends');
|
||||||
|
|
@ -383,7 +384,7 @@ describe('Friends page with data', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('button')
|
cy.get('button')
|
||||||
.contains('Close')
|
.contains('Cancel')
|
||||||
.should('not.be.disabled')
|
.should('not.be.disabled')
|
||||||
.click();
|
.click();
|
||||||
});
|
});
|
||||||
|
|
@ -435,7 +436,7 @@ describe('Friends page with data', () => {
|
||||||
.click();
|
.click();
|
||||||
cy.get('[data-testid=textMessageModal]').within(() => {
|
cy.get('[data-testid=textMessageModal]').within(() => {
|
||||||
cy.get('button')
|
cy.get('button')
|
||||||
.contains('Close')
|
.contains('Cancel')
|
||||||
.should('not.be.disabled')
|
.should('not.be.disabled')
|
||||||
.click();
|
.click();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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 +1,23 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import makeFakeUser from '../../factories/user';
|
|
||||||
|
|
||||||
describe('Unsubscribe from email link', () => {
|
describe('Unsubscribe from email link', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() =>{
|
||||||
// cy.intercept('POST', /\S+\/unsubscribe_user_match\/\S+/, { statusCode: 200, body: { ok: true } });
|
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", () => {
|
it("redirect to home page if tok is not provided", () => {
|
||||||
cy.visit('/unsubscribe');
|
cy.visit('/unsubscribe');
|
||||||
cy.location('pathname').should('eq', '/errors/404');
|
cy.location('pathname').should('eq', '/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("show unsubscribed message", () => {
|
it.only("show unsubscribed message", () => {
|
||||||
cy.visit('/unsubscribe/123');
|
cy.visit('/unsubscribe?tok=123');
|
||||||
// cy.location('search')
|
cy.location('search')
|
||||||
// .should('equal', '?tok=123')
|
.should('equal', '?tok=123')
|
||||||
// .then((s) => new URLSearchParams(s))
|
.then((s) => new URLSearchParams(s))
|
||||||
// .invoke('get', 'tok')
|
.invoke('get', 'tok')
|
||||||
// .should('equal', '123')
|
.should('equal', '123')
|
||||||
cy.contains("You have successfully unsubscribed from JamKazam emails.").should('be.visible');
|
cy.contains("successfully unsubscribed")
|
||||||
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 +1,120 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Top Navigation', () => {
|
describe("Top Navigation", () => {
|
||||||
|
|
||||||
const showSubscribeToUpdates = () => {
|
const showSubscribeToUpdates = () => {
|
||||||
cy.contains('Keep JamKazam Improving').should('exist');
|
cy.contains('Keep JamKazam Improving').should('exist')
|
||||||
cy.contains('Subscribe').should('exist');
|
cy.contains('Subscribe').should('exist')
|
||||||
};
|
}
|
||||||
|
|
||||||
const showProfileDropdown = () => {
|
const showProfileDropdown = () => {
|
||||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('exist');
|
cy.get('[data-testid=navbarTopProfileDropdown]').should('exist')
|
||||||
cy.contains('Sign Out').should('exist');
|
cy.contains("Peter Pan").should('exist')
|
||||||
};
|
//cy.contains("My Profile").should('exist')
|
||||||
|
cy.contains("Sign Out").should('exist')
|
||||||
|
}
|
||||||
|
|
||||||
describe('when user has not logged in', () => {
|
describe("when user has not logged in", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubUnauthenticate();
|
cy.stubUnauthenticate()
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows homepage', () => {
|
it('shows homepage', () => {
|
||||||
cy.visit('/');
|
cy.visit('/')
|
||||||
cy.wait('@getAppFeatures');
|
cy.contains('Home').should('exist')
|
||||||
cy.contains('Sign in').should('exist');
|
showSubscribeToUpdates()
|
||||||
});
|
})
|
||||||
|
|
||||||
it('not allowed to protected page', () => {
|
it("not allowed to protected page", () => {
|
||||||
cy.visit('/friends');
|
cy.visit('/friends')
|
||||||
cy.wait('@getAppFeatures');
|
cy.url().should('include', '/authentication/basic/login')
|
||||||
cy.url().should('include', '/auth/login');
|
cy.contains("Sign in")
|
||||||
cy.contains('Sign in');
|
cy.get('button').should('have.text', 'Sign in')
|
||||||
cy.get('button').should('have.text', 'Sign in');
|
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist')
|
||||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist');
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
})
|
||||||
|
|
||||||
describe('when user has logged in', () => {
|
describe("when user has logged in", () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubAuthenticate();
|
cy.stubAuthenticate()
|
||||||
cy.visit('/');
|
cy.visit('/')
|
||||||
cy.wait('@getAppFeatures');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows user dropdown', () => {
|
it("shows user dropdown", () => {
|
||||||
showSubscribeToUpdates();
|
showSubscribeToUpdates()
|
||||||
showProfileDropdown();
|
showProfileDropdown()
|
||||||
});
|
})
|
||||||
|
|
||||||
it('sign out', () => {
|
it('sign out', () => {
|
||||||
cy.get('[data-testid=navbarTopProfileDropdown]')
|
cy.get('[data-testid=navbarTopProfileDropdown]').contains('Peter Pan').click()
|
||||||
.click();
|
cy.stubUnauthenticate()
|
||||||
cy.stubUnauthenticate();
|
cy.get('[data-testid=navbarTopProfileDropdown]').contains('Sign Out').click()
|
||||||
cy.get('[data-testid=navbarTopProfileDropdown]')
|
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist')
|
||||||
.contains('Sign Out')
|
cy.contains("Home")
|
||||||
.click();
|
})
|
||||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist');
|
})
|
||||||
cy.contains('Sign in');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('header notifications', () => {
|
describe('header notifications', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubAuthenticate();
|
cy.stubAuthenticate()
|
||||||
cy.intercept('GET', /\S+\/my_notifications/, { fixture: 'notifications' });
|
cy.intercept('GET', /\S+\/notifications/, { fixture: 'notifications'} )
|
||||||
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
|
||||||
cy.visit('/');
|
cy.visit('/')
|
||||||
cy.wait('@getAppFeatures');
|
})
|
||||||
});
|
|
||||||
|
|
||||||
it('shows notifications', () => {
|
it('shows notifications', () => {
|
||||||
cy.get('[data-testid=notificationDropdown]').should('not.be.visible');
|
cy.get('[data-testid=notificationDropdown]').should('not.be.visible')
|
||||||
cy.get('.bell-icon').click();
|
cy.get('.notification-indicator').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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
cy.get('[data-testid=notificationDropdown]').should('be.visible');
|
describe('locale switch', () => {
|
||||||
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(() => {
|
beforeEach(() => {
|
||||||
cy.stubAuthenticate();
|
cy.stubAuthenticate()
|
||||||
cy.visit('/');
|
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('left side navigation', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.viewport('macbook-13');
|
||||||
|
cy.stubAuthenticate()
|
||||||
|
cy.visit('/')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows all main and sub menu items opened by default', () => {
|
||||||
|
cy.get('[data-testid=verticalNavigation]' ).contains('Sessions')
|
||||||
|
cy.get('[data-testid=verticalNavigation]' ).contains('Create Session')
|
||||||
|
cy.get('[data-testid=verticalNavigation]' ).contains('Browse Current Sessions')
|
||||||
|
cy.get('[data-testid=verticalNavigation]' ).contains('View Session History')
|
||||||
|
})
|
||||||
|
|
||||||
|
it.only('toggles only one menu on click', () => {
|
||||||
|
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 Current Sessions').should('not.visible')
|
||||||
|
cy.get('[data-testid=verticalNavigation]' ).contains('View 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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
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')
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@ describe('Browse sessions', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('alerts when there is no records', () => {
|
it('alerts when there is no records', () => {
|
||||||
cy.contains('There are no public, open sessions currently available for you to join');
|
cy.contains('No Records!');
|
||||||
cy.contains('create a session').click();
|
|
||||||
cy.url().should('include', '/sessions/new');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -32,32 +30,7 @@ describe('Browse sessions', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('lists the sessions', () => {
|
it('lists the sessions', () => {
|
||||||
const session = makeFakeSession({
|
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.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
cy.get('[data-testid=sessionsListTable] tbody tr').should('have.length', 1);
|
cy.get('[data-testid=sessionsListTable] tbody tr').should('have.length', 1);
|
||||||
|
|
@ -66,31 +39,7 @@ describe('Browse sessions', () => {
|
||||||
describe('session description', () => {
|
describe('session description', () => {
|
||||||
it('when user has provided a description', () => {
|
it('when user has provided a description', () => {
|
||||||
const session = makeFakeSession({
|
const session = makeFakeSession({
|
||||||
description: 'custom description',
|
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.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
|
|
@ -101,31 +50,7 @@ describe('Browse sessions', () => {
|
||||||
const session = makeFakeSession({
|
const session = makeFakeSession({
|
||||||
description: null,
|
description: null,
|
||||||
musician_access: true,
|
musician_access: true,
|
||||||
approval_required: 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.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
|
|
@ -136,31 +61,7 @@ describe('Browse sessions', () => {
|
||||||
const session = makeFakeSession({
|
const session = makeFakeSession({
|
||||||
description: null,
|
description: null,
|
||||||
musician_access: true,
|
musician_access: true,
|
||||||
approval_required: 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.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
|
|
@ -173,31 +74,7 @@ describe('Browse sessions', () => {
|
||||||
const session = makeFakeSession({
|
const session = makeFakeSession({
|
||||||
description: null,
|
description: null,
|
||||||
musician_access: false,
|
musician_access: false,
|
||||||
approval_required: 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.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
|
|
@ -213,30 +90,6 @@ describe('Browse sessions', () => {
|
||||||
sender_id: '1',
|
sender_id: '1',
|
||||||
receiver_id: currentUser.id
|
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.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
|
|
@ -251,8 +104,7 @@ describe('Browse sessions', () => {
|
||||||
participants: [
|
participants: [
|
||||||
{
|
{
|
||||||
user: {
|
user: {
|
||||||
is_friend: true,
|
is_friend: true
|
||||||
name: faker.person.fullName()
|
|
||||||
},
|
},
|
||||||
tracks: [
|
tracks: [
|
||||||
{
|
{
|
||||||
|
|
@ -263,7 +115,7 @@ describe('Browse sessions', () => {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
//console.log('_DEBUG_ session', session);
|
console.log('_DEBUG_ session', session);
|
||||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('YOU HAVE A FRIEND IN THIS SESSION');
|
cy.get('[data-testid=sessionsListTable] tbody tr').contains('YOU HAVE A FRIEND IN THIS SESSION');
|
||||||
|
|
@ -317,13 +169,11 @@ describe('Browse sessions', () => {
|
||||||
tracks: [
|
tracks: [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
instrument: 'Electric Guitar',
|
instrument: 'Guitar'
|
||||||
instrument_id: 'electric_guitar'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
instrument: 'Drums',
|
instrument: 'Drums'
|
||||||
instrument_id: 'drums'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -335,8 +185,7 @@ describe('Browse sessions', () => {
|
||||||
tracks: [
|
tracks: [
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
instrument: 'Bass Guitar',
|
instrument: 'Bass'
|
||||||
instrument_id: 'bass_guitar'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -345,72 +194,33 @@ describe('Browse sessions', () => {
|
||||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
cy.get('[data-testid=sessionsListTable] tbody tr')
|
cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||||
.find(`[data-testid=Participantp1Tracks]`).trigger('mouseover')
|
.find(`[data-testid=Participantp1Tracks]`)
|
||||||
//cy.contains('Electric Guitar');
|
.contains('Guitar');
|
||||||
// cy.get('[data-testid=sessionsListTable] tbody tr')
|
cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||||
// .find(`[data-testid=Participantp1Tracks]`)
|
.find(`[data-testid=Participantp1Tracks]`)
|
||||||
// .contains('Drums');
|
.contains('Drums');
|
||||||
// cy.get('[data-testid=sessionsListTable] tbody tr')
|
cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||||
// .find(`[data-testid=Participantp2Tracks]`)
|
.find(`[data-testid=Participantp2Tracks]`)
|
||||||
// .contains('Bass');
|
.contains('Bass');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('click join button - on a private session', () => {
|
describe('join button', () => {
|
||||||
it('shows toast message', () => {
|
it('shows toast message if private & not invited', () => {
|
||||||
const session = makeFakeSession({
|
const session = makeFakeSession({
|
||||||
participants: [
|
|
||||||
{
|
|
||||||
user: {
|
|
||||||
id: '1',
|
|
||||||
name: 'John Doe'
|
|
||||||
},
|
|
||||||
tracks: [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
instrument: 'Guitar'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
musician_access: true,
|
musician_access: true,
|
||||||
approval_required: true
|
approval_required: true
|
||||||
});
|
});
|
||||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
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.visit('/sessions');
|
||||||
cy.get('[data-testid=sessionsListTable] tbody tr')
|
cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||||
.find('[data-testid=joinBtn]')
|
.find('[data-testid=joinBtn]')
|
||||||
.click();
|
.click();
|
||||||
cy.contains('You have requested to join this private session.');
|
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 and place in the session if public', () => {
|
||||||
it('opens native client', () => {
|
|
||||||
const session = makeFakeSession({
|
const session = makeFakeSession({
|
||||||
participants: [
|
|
||||||
{
|
|
||||||
user: {
|
|
||||||
id: '1',
|
|
||||||
name: 'John Doe'
|
|
||||||
},
|
|
||||||
tracks: [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
instrument: 'Guitar'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
musician_access: true,
|
musician_access: true,
|
||||||
approval_required: false
|
approval_required: false
|
||||||
});
|
});
|
||||||
|
|
@ -418,25 +228,18 @@ describe('Browse sessions', () => {
|
||||||
session.id
|
session.id
|
||||||
}`;
|
}`;
|
||||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
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.visit('/sessions').then(win => {
|
||||||
cy.stub(win, 'open').as('windowOpen');
|
cy.stub(win, 'open').as('windowOpen');
|
||||||
});
|
});
|
||||||
// cy.get('[data-testid=sessionsListTable] tbody tr')
|
cy.get('[data-testid=sessionsListTable] tbody tr')
|
||||||
// .find('[data-testid=joinBtn]')
|
.find('[data-testid=joinBtn]')
|
||||||
// .click();
|
.click();
|
||||||
//cy.get('@windowOpen').should('have.been.calledWith', newUrl);
|
cy.get('@windowOpen').should('have.been.calledWith', newUrl);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.skip('in mobile', () => {
|
describe('in mobile', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport('iphone-6');
|
cy.viewport('iphone-6');
|
||||||
});
|
});
|
||||||
|
|
@ -450,8 +253,7 @@ describe('Browse sessions', () => {
|
||||||
cy.intercept('GET', /\S+\/api\/sessions/, sessions);
|
cy.intercept('GET', /\S+\/api\/sessions/, sessions);
|
||||||
cy.visit('/sessions');
|
cy.visit('/sessions');
|
||||||
cy.get('[data-testid=sessionsSwiper] .swiper-button-prev').should('have.class', 'swiper-button-disabled');
|
cy.get('[data-testid=sessionsSwiper] .swiper-button-prev').should('have.class', 'swiper-button-disabled');
|
||||||
for (let i = 0; i < 4; i++) {
|
for (let i = 0; i < 4; i++) { // 4 because the first one is already visible
|
||||||
// 4 because the first one is already visible
|
|
||||||
cy.get('[data-testid=sessionsSwiper] .swiper-button-next').click();
|
cy.get('[data-testid=sessionsSwiper] .swiper-button-next').click();
|
||||||
cy.wait(500);
|
cy.wait(500);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import useNativeAppCheck from '../../../src/hooks/useNativeAppCheck';
|
|
||||||
|
|
||||||
describe('Create new session', () => {
|
describe('Create new session', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.stubAuthenticate({ id: '6' });
|
cy.stubAuthenticate({ id: '6' });
|
||||||
|
|
@ -60,7 +58,7 @@ describe('Create new session', () => {
|
||||||
cy.get('[data-testid=modal-choose-friends]').should('not.contain', 'Seth Call')
|
cy.get('[data-testid=modal-choose-friends]').should('not.contain', 'Seth Call')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.only("prefill form using saved data in localStorage", () => {
|
it("prefill form using saved data in localStorage", () => {
|
||||||
cy.visit('/sessions/new');
|
cy.visit('/sessions/new');
|
||||||
cy.get('[data-testid=session-privacy]').select("2")
|
cy.get('[data-testid=session-privacy]').select("2")
|
||||||
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
cy.get('[data-testid=autocomplete-text]').type('Dav')
|
||||||
|
|
@ -87,6 +85,4 @@ describe('Create new session', () => {
|
||||||
cy.get('[data-testid=btn-create-session]').should('be.disabled')
|
cy.get('[data-testid=btn-create-session]').should('be.disabled')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
import makeFakeUser from '../../factories/user';
|
|
||||||
|
|
||||||
describe('Session History', () => {
|
|
||||||
const currentUser = makeFakeUser();
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.stubAuthenticate({ id: currentUser.id });
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('When user has no sessions', () => {
|
|
||||||
it('should show no sessions message', () => {
|
|
||||||
cy.intercept('GET', /\S+\/api\/sessions\/history/, {
|
|
||||||
body: []
|
|
||||||
}).as('fetchAllSessions')
|
|
||||||
cy.visit('/sessions/history');
|
|
||||||
cy.wait('@fetchAllSessions');
|
|
||||||
cy.contains('No Records!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,34 +1,38 @@
|
||||||
import { mergePartially, NestedPartial } from 'merge-partially';
|
import { mergePartially, NestedPartial } from 'merge-partially';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
import { IUser } from './user';
|
|
||||||
|
|
||||||
interface ITrack {
|
interface User {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Track {
|
||||||
id: string;
|
id: string;
|
||||||
instrument: string;
|
instrument: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IParticipant {
|
interface Participant {
|
||||||
id: string;
|
id: string;
|
||||||
client_id: string;
|
client_id: string;
|
||||||
user: IUser;
|
user: User;
|
||||||
tracks: ITrack[];
|
tracks: Track[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IInvitations {
|
interface Invitations {
|
||||||
id: string;
|
id: string;
|
||||||
sender_id?: string;
|
sender_id?: string;
|
||||||
receiver_id?: string;
|
receiver_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISession {
|
interface Session {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
participants?: IParticipant[];
|
participants?: Participant[];
|
||||||
invitations?: IInvitations[];
|
invitations?: Invitations[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function makeFakeSession(overrides?: NestedPartial<ISession>): ISession {
|
export default function makeFakeSession(overrides?: NestedPartial<Session>): Session {
|
||||||
return mergePartially.deep(
|
return mergePartially.deep(
|
||||||
{
|
{
|
||||||
id: faker.string.uuid(),
|
id: faker.string.uuid(),
|
||||||
|
|
@ -40,6 +44,7 @@ export default function makeFakeSession(overrides?: NestedPartial<ISession>): IS
|
||||||
client_id: faker.string.uuid(),
|
client_id: faker.string.uuid(),
|
||||||
user: {
|
user: {
|
||||||
id: faker.string.uuid(),
|
id: faker.string.uuid(),
|
||||||
|
name: faker.person.firstName(),
|
||||||
},
|
},
|
||||||
tracks: [{
|
tracks: [{
|
||||||
id: faker.string.uuid(),
|
id: faker.string.uuid(),
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,20 @@
|
||||||
import { mergePartially, NestedPartial } from 'merge-partially';
|
import { mergePartially, NestedPartial } from 'merge-partially';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
|
|
||||||
export interface IUser {
|
interface IUser {
|
||||||
id: string;
|
id: string;
|
||||||
name?: string;
|
firstName: string;
|
||||||
firstName?: string;
|
lastName: string;
|
||||||
lastName?: string;
|
email: string;
|
||||||
email?: string;
|
|
||||||
city?: string;
|
|
||||||
state?: string;
|
|
||||||
country?: string;
|
|
||||||
biography?: string;
|
|
||||||
online?: boolean;
|
|
||||||
musician?: boolean;
|
|
||||||
photo_url?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function makeFakeUser(overrides?: NestedPartial<IUser>): IUser {
|
export default function makeFakeUser(overrides?: NestedPartial<IUser>): IUser {
|
||||||
const fname: string = faker.person.firstName();
|
|
||||||
const lname: string = faker.person.lastName();
|
|
||||||
return mergePartially.deep(
|
return mergePartially.deep(
|
||||||
{
|
{
|
||||||
id: faker.string.uuid(),
|
id: faker.string.uuid(),
|
||||||
email: faker.internet.email(),
|
email: faker.internet.email(),
|
||||||
firstName: fname,
|
firstName: faker.person.firstName(),
|
||||||
lastName: lname,
|
lastName: faker.person.lastName(),
|
||||||
name: fname + ' ' + lname,
|
|
||||||
},
|
},
|
||||||
overrides
|
overrides
|
||||||
);
|
);
|
||||||
|
|
|
||||||
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,562 +0,0 @@
|
||||||
|
|
||||||
{
|
|
||||||
"next": 10,
|
|
||||||
"count": 3756,
|
|
||||||
"jamtracks": [
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"name": "Back in Black",
|
|
||||||
"description": "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the AC DC song \"Back in Black\".",
|
|
||||||
"recording_type": "Cover",
|
|
||||||
"original_artist": "AC DC",
|
|
||||||
"songwriter": null,
|
|
||||||
"publisher": null,
|
|
||||||
"sales_region": "Worldwide",
|
|
||||||
"price": "1.99",
|
|
||||||
"version": "0",
|
|
||||||
"duration": 221,
|
|
||||||
"year": null,
|
|
||||||
"plan_code": "jamtrack-acdc-backinblack",
|
|
||||||
"allow_free": true,
|
|
||||||
"download_price": "2.99",
|
|
||||||
"upgrade_price": "1.0",
|
|
||||||
"tracks": [
|
|
||||||
{
|
|
||||||
"id": "103dea4d-f2a3-4414-8efe-d2ca378dda60",
|
|
||||||
"part": "Master Mix",
|
|
||||||
"instrument": {
|
|
||||||
"id": "computer",
|
|
||||||
"description": "Computer",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Master",
|
|
||||||
"position": 1000,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Master%20Mix-44100-preview-e9a5a63f34b4d523ee1842fff31f88ce.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Master%20Mix-44100-preview-25fcba7ace7086e3cb6b97d7e33ba72e.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Master%20Mix-44100-preview-9f0b072ed9f4b546e170fcdfb302137e.mp3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2755cbdd-0476-4f3b-9ba1-e2da561ddb4e",
|
|
||||||
"part": "Lead",
|
|
||||||
"instrument": {
|
|
||||||
"id": "voice",
|
|
||||||
"description": "Voice",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 1,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Vocal%20-%20Lead-44100-preview-d35c328fc3936dad9a79fe102dc72950.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Vocal%20-%20Lead-44100-preview-b97b37651eae352fae3b3060918c7bcb.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Vocal%20-%20Lead-44100-preview-d35c328fc3936dad9a79fe102dc72950.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "0db7c4e1-5e8d-43fe-bd35-98acd8f68b26",
|
|
||||||
"part": "Drums",
|
|
||||||
"instrument": {
|
|
||||||
"id": "drums",
|
|
||||||
"description": "Drums",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 2,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Drums-44100-preview-03aadceb966caf40b96334bdd00234f6.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Drums-44100-preview-854914e3e0d6fdc5f0794325b0ecaead.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Drums-44100-preview-03aadceb966caf40b96334bdd00234f6.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2cc79ab6-dab8-4905-85e6-0df5f8e087f1",
|
|
||||||
"part": "Bass",
|
|
||||||
"instrument": {
|
|
||||||
"id": "bass guitar",
|
|
||||||
"description": "Bass Guitar",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 3,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Bass-44100-preview-61c334ac87f811bd010ed3a910764c2e.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Bass-44100-preview-4066dafd7b72e9993b0c0fe1dba2b332.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Bass-44100-preview-61c334ac87f811bd010ed3a910764c2e.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "ed1d3487-3b32-442f-9c76-8a36fe3bb643",
|
|
||||||
"part": "Solo",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 4,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Solo-44100-preview-e9fe8572a9ac1022762642cbd92b3c34.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Solo-44100-preview-5fb058042254206cfa9fb4dcb0310b2c.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Solo-44100-preview-e9fe8572a9ac1022762642cbd92b3c34.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "f4ce7c91-7542-4e03-8fc2-68b31683d33e",
|
|
||||||
"part": "Rhythm 1",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 5,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%201-44100-preview-6b498479823d4131a01fa535817d5eab.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%201-44100-preview-f4cbb31dbde3e1a3e6012730a7e0e10f.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%201-44100-preview-6b498479823d4131a01fa535817d5eab.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2d96c7ec-59f1-4d56-8a7f-7f4c75a0ccef",
|
|
||||||
"part": "Rhythm 2",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 6,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%202-44100-preview-a626d7c632560f6737e1b6024141289e.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%202-44100-preview-06a0e5af451f001f3465992efcd34ec0.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%202-44100-preview-a626d7c632560f6737e1b6024141289e.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "fce018ca-c897-4137-aa10-ef56a8e1831f",
|
|
||||||
"part": "Intro Scrapes",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 7,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Intro%20Scrapes-44100-preview-0ddfaa7154e9ba35d05d60477d5dd3e9.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Intro%20Scrapes-44100-preview-f53ce3c5f9dcf81af51560f52635fbb0.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Intro%20Scrapes-44100-preview-0ddfaa7154e9ba35d05d60477d5dd3e9.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "c9b3e0a8-4db0-4d0f-9769-398a6d56506e",
|
|
||||||
"part": "Main",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 8,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Main-44100-preview-234a224f75a97d7ff8f55442ece6fcde.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Main-44100-preview-828c9691f5435dea1c90182fa2618c9b.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Electric%20Guitar%20-%20Main-44100-preview-234a224f75a97d7ff8f55442ece6fcde.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "28c3df07-2a88-45a9-9ae6-3399a5d2eb20",
|
|
||||||
"part": "Sound FX",
|
|
||||||
"instrument": {
|
|
||||||
"id": "computer",
|
|
||||||
"description": "Computer",
|
|
||||||
"created_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"updated_at": "2021-02-02T23:16:46.168Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 9,
|
|
||||||
"preview_mp3_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Sound%20Effects-44100-preview-6c859c73036cd55bceb65f19f2d2f2f3.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Sound%20Effects-44100-preview-f840d8df4c7388f776477139025ee712.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-dev-public.s3.amazonaws.com/jam_track_previews/AC%20DC/Back%20in%20Black/Back%20in%20Black%20Stem%20-%20Sound%20Effects-44100-preview-6c859c73036cd55bceb65f19f2d2f2f3.aac"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"licensor": null,
|
|
||||||
"genres": ["Rock", "Pop"],
|
|
||||||
"added_cart": true,
|
|
||||||
"can_download": true,
|
|
||||||
"purchased": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "531",
|
|
||||||
"name": "1234",
|
|
||||||
"description": "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the Feist song \"1234\".",
|
|
||||||
"recording_type": "Cover",
|
|
||||||
"original_artist": "Feist",
|
|
||||||
"songwriter": null,
|
|
||||||
"publisher": null,
|
|
||||||
"sales_region": "Worldwide",
|
|
||||||
"price": "1.99",
|
|
||||||
"version": "1",
|
|
||||||
"duration": 184,
|
|
||||||
"year": 2007,
|
|
||||||
"plan_code": "jamtrack-feist-1234",
|
|
||||||
"allow_free": true,
|
|
||||||
"download_price": "2.99",
|
|
||||||
"upgrade_price": "1.0",
|
|
||||||
"tracks": [
|
|
||||||
{
|
|
||||||
"id": "b834ce9c-2624-4977-a079-0b1b5d90ad6e",
|
|
||||||
"part": "Clicktrack",
|
|
||||||
"instrument": {
|
|
||||||
"id": "computer",
|
|
||||||
"description": "Computer",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Click",
|
|
||||||
"position": 10000,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234%20-%20Tency%20Music/1234%20Clicktrack-44100-preview-90bed87ea6402ab0f8d283ffe094c95f.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234%20-%20Tency%20Music/1234%20Clicktrack-44100-preview-7198bae1519e40827aff0bd704e2066b.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234%20-%20Tency%20Music/1234%20Clicktrack-44100-preview-90bed87ea6402ab0f8d283ffe094c95f.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "b5a67d64-f94f-453e-9dab-691304275bc2",
|
|
||||||
"part": "Master Mix",
|
|
||||||
"instrument": {
|
|
||||||
"id": "computer",
|
|
||||||
"description": "Computer",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Master",
|
|
||||||
"position": 1000,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1%202%203%204%20Master%20Mix-44100-preview-5fe2a923a614f17dd9c6440b65c1e884.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1%202%203%204%20Master%20Mix-44100-preview-aaefd823d7deaa1bc862eb8ec1e53fe3.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1%202%203%204%20Master%20Mix-44100-preview-6d3edecd174080e88e611984969f1b2d.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "27353eb1-9f2b-487b-9047-93f49446b4db",
|
|
||||||
"part": "Lead",
|
|
||||||
"instrument": {
|
|
||||||
"id": "voice",
|
|
||||||
"description": "Voice",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 1,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Lead-44100-preview-426d923380d10fbdf2d5a4e4108b0de2.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Lead-44100-preview-30eaef3aea1499493cbad76c5c3c8a50.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "78736d23-e657-4922-b145-9f7db40bb36e",
|
|
||||||
"part": "Backing",
|
|
||||||
"instrument": {
|
|
||||||
"id": "voice",
|
|
||||||
"description": "Voice",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 2,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Backing-44100-preview-c0fb7721f3c8cd3253c8c5a6d6b034dd.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Vocal%20-%20Backing-44100-preview-b7145437bbb6b01b566f10ef9009d001.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "1978c439-115b-4214-85a6-beec780310a1",
|
|
||||||
"part": "Drums",
|
|
||||||
"instrument": {
|
|
||||||
"id": "drums",
|
|
||||||
"description": "Drums",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 3,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Drums%20-%20Drums-44100-preview-da3d7e78b9a7b50bea7bcc8f13a7d4b0.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Drums%20-%20Drums-44100-preview-d320dc7600c6d9c08af19b813d6d8176.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "8457c55d-924d-4048-8c5f-46b5c7668552",
|
|
||||||
"part": "Bass",
|
|
||||||
"instrument": {
|
|
||||||
"id": "bass guitar",
|
|
||||||
"description": "Bass Guitar",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 4,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Bass%20Guitar%20-%20Bass-44100-preview-c4b1ce442a9645f6ead0f078afe48d3d.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Bass%20Guitar%20-%20Bass-44100-preview-8a0b0d664802015a219f3320d4d5c0cd.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "ca5d5597-1a19-45b1-9d1b-478f6b6c4b19",
|
|
||||||
"part": "Piano",
|
|
||||||
"instrument": {
|
|
||||||
"id": "piano",
|
|
||||||
"description": "Piano",
|
|
||||||
"created_at": "2014-02-16T13:10:07.059Z",
|
|
||||||
"updated_at": "2014-02-16T13:10:07.059Z",
|
|
||||||
"popularity": 2
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 5,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Piano%20-%20Piano-44100-preview-208fb9e053bb445c1d55ec443809211c.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Piano%20-%20Piano-44100-preview-8940844b3972b39ad9b786805496bc1b.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "755c6c48-fc6c-4dc8-bbf2-9dc0d0a5f2a8",
|
|
||||||
"part": "Acoustic",
|
|
||||||
"instrument": {
|
|
||||||
"id": "acoustic guitar",
|
|
||||||
"description": "Acoustic Guitar",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 6,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Acoustic%20Guitar%20-%20Acoustic-44100-preview-11bde0963b7a833072a49c1096a0b6ef.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Acoustic%20Guitar%20-%20Acoustic-44100-preview-92c44a32feac702880796fd9d6d5f883.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "508bcbaa-4d29-44c0-8cdd-f57fd3fee717",
|
|
||||||
"part": "Banjo",
|
|
||||||
"instrument": {
|
|
||||||
"id": "banjo",
|
|
||||||
"description": "Banjo",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 2
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 7,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Banjo%20-%20Banjo-44100-preview-6ed9db0acb0616651e297b0c057f453d.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Banjo%20-%20Banjo-44100-preview-1e18e0b352e4b05fefa35ce7fd9c84a1.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "6ef8af53-6615-450c-b78b-4310fb0e0395",
|
|
||||||
"part": "Strings",
|
|
||||||
"instrument": {
|
|
||||||
"id": "orchestra",
|
|
||||||
"description": "Orchestra",
|
|
||||||
"created_at": "2015-08-11T16:08:58.806Z",
|
|
||||||
"updated_at": "2015-08-11T16:08:58.806Z",
|
|
||||||
"popularity": 1
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 8,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Orchestra%20-%20Strings-44100-preview-7017822e5edaedbe91fea259cc29666c.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Orchestra%20-%20Strings-44100-preview-70f5d96ed08b1d6a625f21c8be3f691c.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "91427115-63be-49e6-adb1-078f4a7f7ae8",
|
|
||||||
"part": "Trumpet",
|
|
||||||
"instrument": {
|
|
||||||
"id": "trumpet",
|
|
||||||
"description": "Trumpet",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 2
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 9,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Trumpet%20-%20Trumpet-44100-preview-74d7ab8c5af40dc9768176df2afd691a.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Feist/1234/1234%20Stem%20-%20Trumpet%20-%20Trumpet-44100-preview-df093dfebc96d3c22c13ed8d14b44ed0.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"licensor": { "id": "027d90a1-b126-4d5a-8af6-3167296dfb04", "name": "Tency Music" },
|
|
||||||
"genres": ["Folk", "Alternative Rock"],
|
|
||||||
"added_cart": false,
|
|
||||||
"can_download": false,
|
|
||||||
"purchased": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "1437",
|
|
||||||
"name": "18 And Life",
|
|
||||||
"description": "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the Skid Row song \"18 And Life\".",
|
|
||||||
"recording_type": "Cover",
|
|
||||||
"original_artist": "Skid Row",
|
|
||||||
"songwriter": null,
|
|
||||||
"publisher": null,
|
|
||||||
"sales_region": "Worldwide",
|
|
||||||
"price": "1.99",
|
|
||||||
"version": "1",
|
|
||||||
"duration": 227,
|
|
||||||
"year": 1989,
|
|
||||||
"plan_code": "jamtrack-skidrow-18andlife",
|
|
||||||
"allow_free": true,
|
|
||||||
"download_price": "2.99",
|
|
||||||
"upgrade_price": "1.0",
|
|
||||||
"tracks": [
|
|
||||||
{
|
|
||||||
"id": "7c515f02-bebd-4fdd-b30a-81b72ec277b9",
|
|
||||||
"part": "Clicktrack",
|
|
||||||
"instrument": {
|
|
||||||
"id": "computer",
|
|
||||||
"description": "Computer",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Click",
|
|
||||||
"position": 10000,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life%20-%20Tency%20Music/click-44100-preview-424086caaa67c89532635ef0970b2d75.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life%20-%20Tency%20Music/click-44100-preview-d30de7c1353826896110d3ce5f459b23.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life%20-%20Tency%20Music/click-44100-preview-424086caaa67c89532635ef0970b2d75.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "db0a34e4-71e9-4342-b04a-e7c7f068b4fb",
|
|
||||||
"part": "Master Mix",
|
|
||||||
"instrument": {
|
|
||||||
"id": "computer",
|
|
||||||
"description": "Computer",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Master",
|
|
||||||
"position": 1000,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Master%20Mix-44100-preview-5bf5b2872e898dc43875f829e238b62b.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Master%20Mix-44100-preview-3ba1eb2b8ab936212cc299cfb8db34ac.ogg",
|
|
||||||
"preview_aac_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Master%20Mix-44100-preview-146e9a850f83a2f76dc31dc9489dc3aa.aac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cc237bfd-5d87-413b-a460-55d17594f785",
|
|
||||||
"part": "Lead",
|
|
||||||
"instrument": {
|
|
||||||
"id": "voice",
|
|
||||||
"description": "Voice",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 1,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/ld-44100-preview-04a953ee8607a97e8533ea5adf4560a1.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/ld-44100-preview-3486ef50eb889b71208040a0a13de52f.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "a182cf33-1d61-41a8-8e9b-fd23d501885c",
|
|
||||||
"part": "Drums",
|
|
||||||
"instrument": {
|
|
||||||
"id": "drums",
|
|
||||||
"description": "Drums",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 2,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/drums-44100-preview-7ec143f7aa0dc019a2af48c6861c400b.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/drums-44100-preview-6fd8eacb6a8bd35a85e0d4a3a8ec120c.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "406c1f87-c6c1-406f-85a9-05768267ff46",
|
|
||||||
"part": "Bass",
|
|
||||||
"instrument": {
|
|
||||||
"id": "bass guitar",
|
|
||||||
"description": "Bass Guitar",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 3,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/bass-44100-preview-37326a28b8d55f4b61a00eb7406a4da9.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/bass-44100-preview-ff2e87a89ae7693fa8f15a3d065c5833.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "fa46fcd7-0647-4f94-93fd-bddb403abc8b",
|
|
||||||
"part": "Lead",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 4,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Lead-44100-preview-7b8ac822d2a0ccf341c4607919e5125a.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Lead-44100-preview-3d13650573ebe20f939a7e2d661f9fab.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "42e6c71e-715c-48b9-b000-fb7fdabd3fe3",
|
|
||||||
"part": "Rhythm Distorted",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 5,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%20Distorted-44100-preview-4f0312e6d429fa211c873ecd671c2629.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Rhythm%20Distorted-44100-preview-36e75c706ff27930a54be1159afafd9a.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "a16a69b1-2b89-4bca-8039-bb927c7f517f",
|
|
||||||
"part": "Arpeggios Clean",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 6,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Clean-44100-preview-f1f3df4288f9ac9bd8183303099f1a40.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Clean-44100-preview-f8da9761dbed9afd32d636fb0ba2f757.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "8246f3fb-6d35-4a31-9bcd-ef81fd39c66f",
|
|
||||||
"part": "Arpeggios Distorted",
|
|
||||||
"instrument": {
|
|
||||||
"id": "electric guitar",
|
|
||||||
"description": "Electric Guitar",
|
|
||||||
"created_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"updated_at": "2013-01-03T01:57:43.040Z",
|
|
||||||
"popularity": 3
|
|
||||||
},
|
|
||||||
"track_type": "Track",
|
|
||||||
"position": 7,
|
|
||||||
"preview_mp3_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Distorted-44100-preview-2bf523d0f429eaff366691fff0dbcb5f.mp3",
|
|
||||||
"preview_ogg_url": "https://jamkazam-public.s3.amazonaws.com/jam_track_previews/Skid%20Row/18%20And%20Life/18%20And%20Life%20Stem%20-%20Electric%20Guitar%20-%20Arpeggios%20Distorted-44100-preview-e25718a81d9d0a011746def84547f1e9.ogg",
|
|
||||||
"preview_aac_url": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"licensor": { "id": "027d90a1-b126-4d5a-8af6-3167296dfb04", "name": "Tency Music" },
|
|
||||||
"genres": ["Metal", "Rock", "Hard Rock"],
|
|
||||||
"added_cart": false,
|
|
||||||
"can_download": false,
|
|
||||||
"purchased": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,81 +1,74 @@
|
||||||
{
|
[
|
||||||
"next": null,
|
{
|
||||||
"unread_total": 3,
|
"description": "TEXT_MESSAGE",
|
||||||
"notifications": [
|
"source_user_id": "27bd4a30-d1b8-4eea-8454-01a104d59381",
|
||||||
{
|
"target_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
||||||
"description": "TEXT_MESSAGE",
|
"session_id": null,
|
||||||
"source_user_id": "27bd4a30-d1b8-4eea-8454-01a104d59381",
|
"recording_id": null,
|
||||||
"target_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
"invitation_id": null,
|
||||||
"session_id": null,
|
"join_request_id": null,
|
||||||
"recording_id": null,
|
"friend_request_id": null,
|
||||||
"invitation_id": null,
|
"band_id": null,
|
||||||
"join_request_id": null,
|
"band_invitation_id": null,
|
||||||
"friend_request_id": null,
|
"formatted_msg": "TEXT_MESSAGE",
|
||||||
"band_id": null,
|
"message": "Hello",
|
||||||
"band_invitation_id": null,
|
"created_at": "2021-10-07T00:09:57.704Z",
|
||||||
"formatted_msg": "TEXT_MESSAGE",
|
"lesson_session_id": null,
|
||||||
"message": "Hello",
|
"purpose": null,
|
||||||
"created_at": "2021-10-07T00:09:57.704Z",
|
"source_user": {
|
||||||
"lesson_session_id": null,
|
"name": "Nuwan Chaturanga"
|
||||||
"purpose": null,
|
|
||||||
"source_user": {
|
|
||||||
"name": "Nuwan Chaturanga"
|
|
||||||
},
|
|
||||||
"notification_id": "63fcd878-9a22-4419-9cee-8a51a615da97",
|
|
||||||
"fan_access": null,
|
|
||||||
"musician_access": null,
|
|
||||||
"approval_required": null,
|
|
||||||
"read_at": null
|
|
||||||
},
|
},
|
||||||
{
|
"notification_id": "63fcd878-9a22-4419-9cee-8a51a615da97",
|
||||||
"description": "FRIEND_REQUEST",
|
"fan_access": null,
|
||||||
"source_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
"musician_access": null,
|
||||||
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
"approval_required": null
|
||||||
"session_id": null,
|
},
|
||||||
"recording_id": null,
|
{
|
||||||
"invitation_id": null,
|
"description": "FRIEND_REQUEST",
|
||||||
"join_request_id": null,
|
"source_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
||||||
"friend_request_id": "7c842904-24f5-4515-8886-0c3d25ee641b",
|
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
||||||
"band_id": null,
|
"session_id": null,
|
||||||
"band_invitation_id": null,
|
"recording_id": null,
|
||||||
"formatted_msg": "Seth Call has sent you a friend request.",
|
"invitation_id": null,
|
||||||
"message": null,
|
"join_request_id": null,
|
||||||
"created_at": "2021-10-15T05:36:48.527Z",
|
"friend_request_id": "7c842904-24f5-4515-8886-0c3d25ee641b",
|
||||||
"lesson_session_id": null,
|
"band_id": null,
|
||||||
"purpose": null,
|
"band_invitation_id": null,
|
||||||
"source_user": {
|
"formatted_msg": "Seth Call has sent you a friend request.",
|
||||||
"name": "Seth Call"
|
"message": null,
|
||||||
},
|
"created_at": "2021-10-15T05:36:48.527Z",
|
||||||
"notification_id": "3364b5f1-8946-46a3-b635-86d89d237849",
|
"lesson_session_id": null,
|
||||||
"fan_access": null,
|
"purpose": null,
|
||||||
"musician_access": null,
|
"source_user": {
|
||||||
"approval_required": null,
|
"name": "Seth Call"
|
||||||
"read_at": null
|
|
||||||
},
|
},
|
||||||
{
|
"notification_id": "3364b5f1-8946-46a3-b635-86d89d237849",
|
||||||
"description": "FRIEND_REQUEST_ACCEPTED",
|
"fan_access": null,
|
||||||
"source_user_id": "29becbf4-8be5-4078-9405-0edadc9fa42d",
|
"musician_access": null,
|
||||||
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
"approval_required": null
|
||||||
"session_id": null,
|
},
|
||||||
"recording_id": null,
|
{
|
||||||
"invitation_id": null,
|
"description": "FRIEND_REQUEST_ACCEPTED",
|
||||||
"join_request_id": null,
|
"source_user_id": "29becbf4-8be5-4078-9405-0edadc9fa42d",
|
||||||
"friend_request_id": null,
|
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
||||||
"band_id": null,
|
"session_id": null,
|
||||||
"band_invitation_id": null,
|
"recording_id": null,
|
||||||
"formatted_msg": "Peter Walker has accepted your friend request.",
|
"invitation_id": null,
|
||||||
"message": null,
|
"join_request_id": null,
|
||||||
"created_at": "2021-10-05T12:38:53.134Z",
|
"friend_request_id": null,
|
||||||
"lesson_session_id": null,
|
"band_id": null,
|
||||||
"purpose": null,
|
"band_invitation_id": null,
|
||||||
"source_user": {
|
"formatted_msg": "Peter Walker has accepted your friend request.",
|
||||||
"name": "Peter Walker"
|
"message": null,
|
||||||
},
|
"created_at": "2021-10-05T12:38:53.134Z",
|
||||||
"notification_id": "bb9269f3-721c-48cd-9bf6-bcff72877198",
|
"lesson_session_id": null,
|
||||||
"fan_access": null,
|
"purpose": null,
|
||||||
"musician_access": null,
|
"source_user": {
|
||||||
"approval_required": null,
|
"name": "Peter Walker"
|
||||||
"read_at": null
|
},
|
||||||
}
|
"notification_id": "bb9269f3-721c-48cd-9bf6-bcff72877198",
|
||||||
]
|
"fan_access": null,
|
||||||
}
|
"musician_access": null,
|
||||||
|
"approval_required": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
{
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"id": "a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6",
|
|
||||||
"created_at": "2022-12-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "q7r8s9t0-u1v2-w3x4-y5z6-a7b8c9d0e1f2",
|
|
||||||
"created_at": "2022-11-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "g3h4i5j6-k7l8-m9n0-o1p2-q3r4s5t6u7v8w9x0",
|
|
||||||
"created_at": "2022-10-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "y1z2a3b4-c5d6-e7f8-g9h0-i1j2k3l4m5n6o7",
|
|
||||||
"created_at": "2022-09-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "p8q9r0s1-t2u3-v4w5-x6y7-z8a9b0c1d2e3f4",
|
|
||||||
"created_at": "2022-08-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "g5h6i7j8-k9l0-m1n2-o3p4-q5r6s7t8u9v0w1x2",
|
|
||||||
"created_at": "2022-07-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "y3z4a5b6-c7d8-e9f0-g1h2-i3j4k5l6m7n8o9",
|
|
||||||
"created_at": "2022-06-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "p2q3r4s5-t6u7-v8w9-x0y1-z2a3b4c5d6e7f8",
|
|
||||||
"created_at": "2022-05-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "g9h0i1j2-k3l4-m5n6-o7p8-q9r0s1t2u3v4w5x6",
|
|
||||||
"created_at": "2022-04-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "y7z8a9b0-c1d2-e3f4-g5h6-i7j8k9l0m1n2o3p4",
|
|
||||||
"created_at": "2022-03-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
{
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"id": "a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6",
|
|
||||||
"created_at": "2022-02-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "q7r8s9t0-u1v2-w3x4-y5z6-a7b8c9d0e1f2",
|
|
||||||
"created_at": "2022-01-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "g3h4i5j6-k7l8-m9n0-o1p2-q3r4s5t6u7v8w9x0",
|
|
||||||
"created_at": "2021-12-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "y1z2a3b4-c5d6-e7f8-g9h0-i1j2k3l4m5n6o7",
|
|
||||||
"created_at": "2021-11-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "p8q9r0s1-t2u3-v4w5-x6y7-z8a9b0c1d2e3f4",
|
|
||||||
"created_at": "2021-10-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "g5h6i7j8-k9l0-m1n2-o3p4-q5r6s7t8u9v0w1x2",
|
|
||||||
"created_at": "2021-09-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "y3z4a5b6-c7d8-e9f0-g1h2-i3j4k5l6m7n8o9",
|
|
||||||
"created_at": "2021-08-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "p2q3r4s5-t6u7-v8w9-x0y1-z2a3b4c5d6e7f8",
|
|
||||||
"created_at": "2021-07-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "g9h0i1j2-k3l4-m5n6-o7p8-q9r0s1t2u3v4w5x6",
|
|
||||||
"created_at": "2021-06-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "y7z8a9b0-c1d2-e3f4-g5h6-i7j8k9l0m1n2o3p4",
|
|
||||||
"created_at": "2021-05-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6",
|
|
||||||
"created_at": "2021-04-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"id": "a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6",
|
|
||||||
"created_at": "2021-03-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "q7r8s9t0-u1v2-w3x4-y5z6-a7b8c9d0e1f2",
|
|
||||||
"created_at": "2021-02-01T00:00:00Z",
|
|
||||||
"total_in_cents": 999,
|
|
||||||
"description": "JamKazam Gold Plan - Monthly",
|
|
||||||
"status": "paid"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -50,6 +50,7 @@
|
||||||
{ "id": "005a7c78-db8b-4f72-a51f-d64d579c22b3", "service_type": "facebook", "username": "testuser" },
|
{ "id": "005a7c78-db8b-4f72-a51f-d64d579c22b3", "service_type": "facebook", "username": "testuser" },
|
||||||
{ "id": "005a7c78-db8b-4f72-a51f-d64d579c22b4", "service_type": "twitter", "username": "testuser" }
|
{ "id": "005a7c78-db8b-4f72-a51f-d64d579c22b4", "service_type": "twitter", "username": "testuser" }
|
||||||
],
|
],
|
||||||
|
"performance_samples": [],
|
||||||
"genres": [
|
"genres": [
|
||||||
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "profile" },
|
{ "genre_id": "classical", "player_type": "JamRuby::User", "genre_type": "profile" },
|
||||||
{ "genre_id": "blues", "player_type": "JamRuby::User", "genre_type": "free_sessions" }
|
{ "genre_id": "blues", "player_type": "JamRuby::User", "genre_type": "free_sessions" }
|
||||||
|
|
@ -73,16 +74,6 @@
|
||||||
{ "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1, "instrument_id": "acoustic guitar" },
|
{ "description": "Acoustic Guitar", "proficiency_level": 3, "priority": 1, "instrument_id": "acoustic guitar" },
|
||||||
{ "description": "Keyboard", "proficiency_level": 3, "priority": 8, "instrument_id": "keyboard" }
|
{ "description": "Keyboard", "proficiency_level": 3, "priority": 8, "instrument_id": "keyboard" }
|
||||||
],
|
],
|
||||||
"performance_samples": [
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"service_type": "youtube",
|
|
||||||
"claimed_recording": {
|
|
||||||
"id": "1",
|
|
||||||
"name": "Test Recording1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"is_friend": false,
|
"is_friend": false,
|
||||||
"is_following": false,
|
"is_following": false,
|
||||||
"is_liking": false,
|
"is_liking": false,
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ Cypress.Commands.add('stubAuthenticate', (attrs = {}) => {
|
||||||
first_name: 'Peter',
|
first_name: 'Peter',
|
||||||
last_name: 'Pan',
|
last_name: 'Pan',
|
||||||
name: 'Peter Pan',
|
name: 'Peter Pan',
|
||||||
email: 'peter@example.com',
|
|
||||||
photo_url: ''
|
photo_url: ''
|
||||||
}
|
}
|
||||||
const currentUserAtrs = {...defaultAttrs, ...attrs}
|
const currentUserAtrs = {...defaultAttrs, ...attrs}
|
||||||
|
|
@ -48,58 +47,3 @@ Cypress.Commands.add('stubUnauthenticate', () => {
|
||||||
body: {}
|
body: {}
|
||||||
}).as('getUnauthenticateCurrentUser')
|
}).as('getUnauthenticateCurrentUser')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Cypress.Commands.add('stubGonSubscriptionCodes', () => {
|
|
||||||
Cypress.on('window:before:load', win => {
|
|
||||||
win.gon = {
|
|
||||||
//session variables
|
|
||||||
global: {
|
|
||||||
subscription_codes: [
|
|
||||||
{
|
|
||||||
id: null,
|
|
||||||
name: 'Free',
|
|
||||||
price: 0,
|
|
||||||
cycle: 'month'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'jamsubsilver',
|
|
||||||
name: 'Silver',
|
|
||||||
price: 4.99,
|
|
||||||
cycle: 'month'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'jamsubgold',
|
|
||||||
name: 'Gold',
|
|
||||||
price: 9.99,
|
|
||||||
cycle: 'month'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'jamsubplatinum',
|
|
||||||
name: 'Platinum',
|
|
||||||
price: 19.99,
|
|
||||||
cycle: 'month'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'jamsubsilveryearly',
|
|
||||||
name: 'Silver',
|
|
||||||
price: 49.99,
|
|
||||||
cycle: 'year'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'jamsubgoldyearly',
|
|
||||||
name: 'Gold',
|
|
||||||
price: 99.99,
|
|
||||||
cycle: 'year'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'jamsubplatinumyearly',
|
|
||||||
name: 'Platinum',
|
|
||||||
price: 199.99,
|
|
||||||
cycle: 'year'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -20,34 +20,4 @@ import './commands'
|
||||||
// require('./commands')
|
// require('./commands')
|
||||||
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// Intercept the GET /app_features request and return an empty array
|
|
||||||
// to simulate the backend returning an empty set of app features
|
|
||||||
cy.intercept('GET', /\S+\/app_features/, {
|
|
||||||
statusCode: 200,
|
|
||||||
body: [],
|
|
||||||
}).as('getAppFeatures');
|
|
||||||
|
|
||||||
cy.intercept('GET', /\S+\/users\/\S+\/profile/, {
|
|
||||||
statusCode: 200,
|
|
||||||
body: {
|
|
||||||
id: 1,
|
|
||||||
name: 'Jane Doe',
|
|
||||||
email: 'jane@example.com',
|
|
||||||
},
|
|
||||||
}).as('getUserProfile');
|
|
||||||
|
|
||||||
cy.intercept('GET', /\S+\/users\/\S+\/my_notifications/, {
|
|
||||||
statusCode: 200,
|
|
||||||
body: [],
|
|
||||||
}).as('getMyNotifications');
|
|
||||||
|
|
||||||
cy.intercept('GET', /\S+\/users\/\S+\/friends/, {
|
|
||||||
statusCode: 200,
|
|
||||||
body: [],
|
|
||||||
}).as('getMyFriends');
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ const cleanCSS = require('gulp-clean-css');
|
||||||
-----------------------------------------------*/
|
-----------------------------------------------*/
|
||||||
gulp.task('scss', () =>
|
gulp.task('scss', () =>
|
||||||
gulp
|
gulp
|
||||||
.src('src/assets/scss/theme.scss')
|
.src('src/assets/scss/*.scss')
|
||||||
.pipe(plumber())
|
.pipe(plumber())
|
||||||
.pipe(sourcemaps.init())
|
.pipe(sourcemaps.init())
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
@ -49,7 +49,7 @@ gulp.task('scss:dark', () =>
|
||||||
|
|
||||||
gulp.task('scss:rtl', () =>
|
gulp.task('scss:rtl', () =>
|
||||||
gulp
|
gulp
|
||||||
.src('src/assets/scss/theme.scss')
|
.src('src/assets/scss/*.scss')
|
||||||
.pipe(plumber())
|
.pipe(plumber())
|
||||||
.pipe(sourcemaps.init())
|
.pipe(sourcemaps.init())
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -4,7 +4,6 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@farfetch/react-context-responsive": "^1.5.0",
|
"@farfetch/react-context-responsive": "^1.5.0",
|
||||||
"@fingerprintjs/fingerprintjs": "^4.6.0",
|
|
||||||
"@fortawesome/fontawesome-free": "^5.15.1",
|
"@fortawesome/fontawesome-free": "^5.15.1",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.30",
|
"@fortawesome/fontawesome-svg-core": "^1.2.30",
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.14.0",
|
"@fortawesome/free-brands-svg-icons": "^5.14.0",
|
||||||
|
|
@ -25,17 +24,12 @@
|
||||||
"chance": "^1.1.8",
|
"chance": "^1.1.8",
|
||||||
"chart.js": "^2.9.3",
|
"chart.js": "^2.9.3",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"creditcard.js": "^3.0.33",
|
|
||||||
"custom-protocol-check": "^1.4.0",
|
|
||||||
"echarts": "^4.9.0",
|
"echarts": "^4.9.0",
|
||||||
"echarts-for-react": "^2.0.16",
|
"echarts-for-react": "^2.0.16",
|
||||||
"element-resize-event": "^3.0.3",
|
"element-resize-event": "^3.0.3",
|
||||||
"emoji-mart": "^3.0.0",
|
"emoji-mart": "^3.0.0",
|
||||||
"faker": "^5.5.3",
|
|
||||||
"filestack-js": "^3.32.3",
|
|
||||||
"fuse.js": "^6.4.3",
|
"fuse.js": "^6.4.3",
|
||||||
"google-maps-react": "^2.0.6",
|
"google-maps-react": "^2.0.6",
|
||||||
"howler": "^2.2.4",
|
|
||||||
"i18next": "^21.3.3",
|
"i18next": "^21.3.3",
|
||||||
"is_js": "^0.9.0",
|
"is_js": "^0.9.0",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
|
|
@ -43,7 +37,7 @@
|
||||||
"leaflet.tilelayer.colorfilter": "^1.2.5",
|
"leaflet.tilelayer.colorfilter": "^1.2.5",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"merge-partially": "^2.0.2",
|
"merge-partially": "^2.0.2",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.28.0",
|
||||||
"plyr": "3.6.2",
|
"plyr": "3.6.2",
|
||||||
"prism-react-renderer": "^0.1.7",
|
"prism-react-renderer": "^0.1.7",
|
||||||
"prism-themes": "^1.4.0",
|
"prism-themes": "^1.4.0",
|
||||||
|
|
@ -61,8 +55,6 @@
|
||||||
"react-dropzone": "^10.2.2",
|
"react-dropzone": "^10.2.2",
|
||||||
"react-es6-progressbar.js": "^1.1.0",
|
"react-es6-progressbar.js": "^1.1.0",
|
||||||
"react-flatpickr": "^3.10.6",
|
"react-flatpickr": "^3.10.6",
|
||||||
"react-ga4": "^2.1.0",
|
|
||||||
"react-google-recaptcha": "^3.1.0",
|
|
||||||
"react-hook-form": "^7.11.1",
|
"react-hook-form": "^7.11.1",
|
||||||
"react-https-redirect": "^1.1.0",
|
"react-https-redirect": "^1.1.0",
|
||||||
"react-i18next": "^11.12.0",
|
"react-i18next": "^11.12.0",
|
||||||
|
|
@ -81,13 +73,13 @@
|
||||||
"react-select": "^3.1.0",
|
"react-select": "^3.1.0",
|
||||||
"react-simple-code-editor": "^0.9.15",
|
"react-simple-code-editor": "^0.9.15",
|
||||||
"react-slick": "^0.25.2",
|
"react-slick": "^0.25.2",
|
||||||
"react-slider": "^2.0.6",
|
|
||||||
"react-timeago": "^6.2.1",
|
"react-timeago": "^6.2.1",
|
||||||
"react-toastify": "^5.5.0",
|
"react-toastify": "^5.5.0",
|
||||||
"react-typed": "^1.2.0",
|
"react-typed": "^1.2.0",
|
||||||
"reactstrap": "^8.6.0",
|
"reactstrap": "^8.6.0",
|
||||||
"slick-carousel": "^1.8.1",
|
"slick-carousel": "^1.8.1",
|
||||||
"uuid": "^3.4.0"
|
"uuid": "^3.4.0",
|
||||||
|
"faker": "^5.5.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|
@ -102,12 +94,11 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^8.2.0",
|
"@faker-js/faker": "^8.2.0",
|
||||||
"@playwright/test": "^1.40.0",
|
"@playwright/test": "^1.15.2",
|
||||||
"browser-sync": "^2.29.3",
|
"browser-sync": "^2.26.12",
|
||||||
"eslint-config-prettier": "^4.2.0",
|
"eslint-config-prettier": "^4.2.0",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-react": "^7.20.6",
|
"eslint-plugin-react": "^7.20.6",
|
||||||
"eslint-plugin-react-hooks": "^1.7.0",
|
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-autoprefixer": "^6.1.0",
|
"gulp-autoprefixer": "^6.1.0",
|
||||||
"gulp-clean-css": "^4.3.0",
|
"gulp-clean-css": "^4.3.0",
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,23 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg width="100%" height="100%" viewBox="0 0 1382 1279" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
|
||||||
<g transform="matrix(0,1216.92,1216.92,0,705.09,-29.8146)">
|
|
||||||
<g id="Layer-2" serif:id="Layer 2">
|
|
||||||
<path d="M0.544,-0.515C0.828,-0.515 1.059,-0.285 1.059,-0C1.059,0.285 0.828,0.515 0.544,0.515C0.259,0.515 0.029,0.285 0.029,-0C0.029,-0.285 0.259,-0.515 0.544,-0.515Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g id="svg2">
|
|
||||||
<g transform="matrix(1,0,0,1,506.212,879.191)">
|
|
||||||
<path d="M0,-154.033C-2.474,-154.033 -5.313,-153.848 -8.173,-153.3L-9.523,-154.65L-31.649,-132.524C-3.542,-126.838 27.743,-109.611 54.701,-82.653C80.678,-56.677 97.623,-26.68 103.909,0.617L125.571,-21.044C126.606,-27.607 126.092,-35.629 123.906,-44.621C118.523,-66.773 103.788,-91.125 83.481,-111.433C69.838,-125.077 54.383,-136.259 38.787,-143.771C24.855,-150.484 11.443,-154.033 0.004,-154.033L0,-154.033Z" style="fill:white;fill-rule:nonzero;"/>
|
|
||||||
</g>
|
|
||||||
<g transform="matrix(1,0,0,1,1047.59,812.445)">
|
|
||||||
<path d="M0,-507.546C-18,-523.546 -68,-504.459 -68,-504.459L-68,-475.459L-101,-475.459L-278.654,-297.806C-305.358,-307.529 -331.964,-304.975 -348.535,-288.403C-348.856,-288.083 -349.147,-287.739 -349.458,-287.411C-352.297,-285.827 -354.972,-283.839 -357.385,-281.425L-521.669,-117.142C-493.562,-111.455 -462.276,-94.229 -435.318,-67.271C-409.342,-41.294 -392.397,-11.297 -386.11,16L-223.034,-147.075C-223.021,-147.089 -223.009,-147.105 -222.995,-147.116C-219.827,-149.073 -216.869,-151.37 -214.186,-154.054C-196.466,-171.772 -194.776,-200.962 -206.983,-229.477L-24,-412.46L-30,-440.459L2,-446.459C2,-446.459 18,-491.546 0,-507.546" style="fill:white;fill-rule:nonzero;"/>
|
|
||||||
</g>
|
|
||||||
<g transform="matrix(1,0,0,1,387.793,389.887)">
|
|
||||||
<path d="M0,480.02C6.414,473.606 15.482,472.258 21.961,472.258L21.965,472.258C40.656,472.258 62.085,482.528 79.286,499.729C93.4,513.843 103.109,531.325 105.923,547.69C107.259,555.464 108.137,569.874 98.994,579.015C92.578,585.432 83.511,586.779 77.034,586.779C65.598,586.779 53.138,582.929 41.248,576.007C59.173,571.815 68.087,566.259 71.21,557.708C74.738,548.046 69.982,536.425 55.308,518.85C48.082,510.198 37.366,505.993 22.547,505.993C14.982,505.993 7.308,507.006 -0.115,507.987C-2.572,508.311 -4.976,508.628 -7.297,508.897C-8.341,500.815 -8.253,488.273 0,480.02M881.888,28.315C881.909,27.528 881.772,26.673 881.425,25.76L881.43,25.758L864.385,-14.544C864.338,-14.654 864.29,-14.768 864.24,-14.884C863.968,-15.528 863.808,-15.906 863.786,-15.957L863.754,-15.944C863.409,-16.629 862.982,-17.33 862.412,-17.934C814.184,-120.121 738.177,-205.502 641.446,-265.845C592.524,-296.364 539.249,-319.919 483.101,-335.857C427.332,-351.688 369.766,-359.714 312.001,-359.714C152.069,-359.714 2.72,-298.442 -108.537,-187.183C-174.663,-121.058 -225.269,-38.981 -254.883,50.173C-284.492,139.309 -293.085,235.418 -279.735,328.11C-269.758,397.378 -239.036,460.967 -193.227,507.163C-169.749,530.837 -143.033,549.315 -113.818,562.083C-83.092,575.512 -50.22,582.321 -16.116,582.321C-8.628,582.321 -1.049,581.981 6.571,581.318C28.379,601.205 54.305,611.779 77.034,611.779C92.498,611.779 106.484,606.881 116.672,596.693C118.715,594.65 120.52,592.438 122.141,590.109L192.627,519.623C193.661,513.059 193.147,505.039 190.962,496.046C185.579,473.894 170.844,449.543 150.536,429.234C136.893,415.59 121.439,404.409 105.843,396.896C91.91,390.183 78.499,386.634 67.06,386.634L67.056,386.634C64.582,386.634 61.742,386.819 58.883,387.368L57.532,386.017L-12.853,456.403C-14.665,458.214 -16.23,460.178 -17.573,462.243C-17.607,462.277 -17.644,462.308 -17.678,462.342C-29.263,473.928 -33.994,490.42 -32.477,508.418C-68.221,503.794 -101.782,488.342 -130.175,463.302C-160.397,436.651 -182.628,400.421 -192.773,361.29C-215.521,273.543 -212.216,178.442 -183.218,86.269C-169.219,41.772 -149.57,-0.79 -124.817,-40.235C-99.785,-80.125 -70.023,-116.034 -36.357,-146.966C12.265,-191.639 67.591,-225.83 128.083,-248.589C185.326,-270.125 246.008,-281.045 308.442,-281.045C370.17,-281.045 431.402,-270.437 490.438,-249.517C549.446,-228.607 603.681,-198.309 651.635,-159.465C701.102,-119.396 741.967,-71.723 773.098,-17.77C806.02,39.288 827.213,102.071 836.09,168.835C843.646,225.67 841.637,283.236 830.116,339.932C818.887,395.194 798.935,448.225 770.812,497.553C742.676,546.908 707.203,591.077 665.38,628.832C622.43,667.606 573.873,698.592 521.06,720.931C457.531,747.801 386.94,762.004 316.918,762.006C270.199,762.006 223.948,755.852 179.45,743.713C126.396,729.239 76.185,706.575 30.214,676.349C22.573,671.326 15.793,665.93 9.236,660.713C-8.354,646.716 -24.969,633.497 -51.561,633.497C-51.883,633.497 -52.202,633.499 -52.526,633.502C-53.249,633.51 -53.974,633.515 -54.695,633.515C-82.262,633.515 -110.339,627.374 -138.146,615.26L-161.46,605.105L-145.145,624.611C-116.379,659.002 -83.567,690.177 -47.623,717.269C-12.579,743.682 25.619,766.355 65.91,784.656C145.235,820.686 233.265,839.732 320.48,839.734L320.491,839.734C424.057,839.734 525.681,813.159 614.362,762.886C741.202,690.982 837.576,573.648 885.73,432.499C931.153,299.356 929.635,156.816 881.888,28.315" style="fill:white;fill-rule:nonzero;"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.650791,0.759257,0.759257,-0.650791,0.189886,-0.412854)"><stop offset="0" style="stop-color:rgb(107,108,111);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(35,31,32);stop-opacity:1"/></linearGradient>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 5.8 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 158 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 158 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 158 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue