Compare commits
3 Commits
develop
...
feature/al
| Author | SHA1 | Date |
|---|---|---|
|
|
0b5bb77078 | |
|
|
77e966dea4 | |
|
|
7cd9a43c25 |
|
|
@ -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!"
|
||||
|
|
@ -2,7 +2,7 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
|
|||
|
||||
menu :label => 'Quarterly Reports', :parent => 'Affiliates'
|
||||
|
||||
config.sort_order = 'year desc, quarter desc, due_amount_in_cents desc'
|
||||
config.sort_order = 'due_amount_in_cents DESC'
|
||||
config.batch_actions = false
|
||||
config.clear_action_items!
|
||||
config.filters = true
|
||||
|
|
@ -14,32 +14,18 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
|
|||
filter :quarter
|
||||
filter :closed
|
||||
filter :paid
|
||||
filter :jamtracks_sold
|
||||
filter :subscriptions_count
|
||||
filter :due_amount_in_cents
|
||||
|
||||
form :partial => 'form'
|
||||
|
||||
scope("Sorted By Due Amount", default: true) { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') }
|
||||
scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.order('year desc, quarter desc, jamtracks_sold desc') }
|
||||
scope("Sorted By Subs", default: false) { |scope| scope.order('year desc, quarter desc, subscriptions_count desc') }
|
||||
scope("Sorted By Newest First") { |scope| scope.order('year desc, quarter desc, id desc') }
|
||||
scope("Any") { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') }
|
||||
|
||||
|
||||
index do
|
||||
|
||||
# default_actions # use this for all view/edit/delete links
|
||||
|
||||
column 'Year' do |oo| oo.year end
|
||||
column 'Quarter' do |oo| oo.quarter end
|
||||
column 'Partner Id' do |oo| oo.affiliate_partner.id end
|
||||
column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end
|
||||
column "Tot ($)" do |oo| sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f) end
|
||||
column "Sub ($)" do |oo| sprintf("$%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f) end
|
||||
column "Jam ($)" do |oo| sprintf("$%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f) end
|
||||
column 'JamTracks' do |oo| oo.jamtracks_sold end
|
||||
column 'Subscriptions' do |oo| oo.subscriptions_count end
|
||||
column "Due (\u00A2)" do |oo| oo.due_amount_in_cents end
|
||||
column 'JamTracks Sold' do |oo| oo.jamtracks_sold end
|
||||
column 'Paid' do |oo| oo.paid end
|
||||
column 'Closed' do |oo| oo.paid end
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ ActiveAdmin.register JamRuby::AffiliateTrafficTotal, :as => 'Affiliate Daily Sta
|
|||
# default_actions # use this for all view/edit/delete links
|
||||
|
||||
column 'Day' do |oo| oo.day end
|
||||
column 'Partner ID' do |oo| oo.affiliate_partner.id end
|
||||
column 'Partner Name' do |oo| oo.affiliate_partner.display_name end
|
||||
column 'Partner User' do |oo| link_to(oo.affiliate_partner.partner_user.name, admin_user_path(oo.affiliate_partner.partner_user.id), { :title => oo.affiliate_partner.partner_user.name }) end
|
||||
column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end
|
||||
column 'Signups' do |oo| oo.signups end
|
||||
column 'Visits' do |oo| oo.visits end
|
||||
|
||||
|
|
@ -33,16 +31,6 @@ ActiveAdmin.register JamRuby::AffiliateTrafficTotal, :as => 'Affiliate Daily Sta
|
|||
|
||||
|
||||
controller do
|
||||
def scoped_collection
|
||||
rel = end_of_association_chain
|
||||
.includes([:affiliate_partner])
|
||||
.order('day DESC')
|
||||
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
||||
qq = ['affiliate_partner_id = ?', ref_id]
|
||||
else
|
||||
qq = ['affiliate_partner_id IS NOT NULL']
|
||||
end
|
||||
@users ||= rel.where(qq)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,32 +8,27 @@ ActiveAdmin.register JamRuby::User, :as => 'Referrals' do
|
|||
config.filters = true
|
||||
|
||||
filter :affiliate_referral
|
||||
filter :email
|
||||
|
||||
## scope("Has Signups", default: true) { |scope| scope.where('visits != 0 or signups != 0').order('day desc') }
|
||||
|
||||
index do
|
||||
column 'User' do |oo| link_to(oo.name, oo.admin_url, {:title => oo.name}) end
|
||||
column 'User Email' do |oo| oo.email end
|
||||
column 'Email' do |oo| oo.email end
|
||||
column 'Created' do |oo| oo.created_at end
|
||||
column 'Partner ID' do |oo| oo.affiliate_referral.id end
|
||||
column 'Partner Name' do |oo| oo.affiliate_referral.display_name end
|
||||
column 'Partner User' do |oo| link_to(oo.affiliate_referral.partner_user.name, admin_user_path(oo.affiliate_referral.partner_user.id), { :title => oo.affiliate_referral.partner_user.name }) end
|
||||
column 'Partner' do |oo| oo.affiliate_referral.display_name end
|
||||
end
|
||||
|
||||
controller do
|
||||
|
||||
def scoped_collection
|
||||
rel = end_of_association_chain
|
||||
.includes([:affiliate_referral])
|
||||
.order('created_at DESC')
|
||||
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
||||
qq = ['affiliate_referral_id = ?', ref_id]
|
||||
else
|
||||
qq = ['affiliate_referral_id IS NOT NULL']
|
||||
def scoped_collection
|
||||
rel = end_of_association_chain
|
||||
.includes([:affiliate_referral])
|
||||
.order('created_at DESC')
|
||||
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
|
||||
qq = ['affiliate_referral_id = ?', ref_id]
|
||||
else
|
||||
qq = ['affiliate_referral_id IS NOT NULL']
|
||||
end
|
||||
@users ||= rel.where(qq)
|
||||
end
|
||||
@users ||= rel.where(qq)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,35 +5,19 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
|||
config.sort_order = 'referral_user_count DESC'
|
||||
config.batch_actions = false
|
||||
# config.clear_action_items!
|
||||
config.filters = true
|
||||
config.per_page = 100
|
||||
config.filters = false
|
||||
config.per_page = 50
|
||||
config.paginate = true
|
||||
|
||||
#form :partial => 'form'
|
||||
|
||||
|
||||
#filter :partner_user
|
||||
filter :partner_name
|
||||
filter :id
|
||||
filter :current_quarter_in_cents
|
||||
filter :cumulative_earnings_in_cents
|
||||
filter :jamtracks_sold
|
||||
filter :subscriptions_count
|
||||
filter :referral_user_count
|
||||
|
||||
scope("Sorted By Current Quarter", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('current_quarter_in_cents desc') }
|
||||
scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('jamtracks_sold desc') }
|
||||
scope("Sorted By Subs", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('subscriptions_count desc') }
|
||||
scope("Sorted By Signups", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
|
||||
scope("Sorted By Newest First") { |scope| scope.where('partner_user_id IS NOT NULL').order('id desc') }
|
||||
scope("Any") { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
|
||||
scope("Active", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
|
||||
scope("Unpaid") { |partner| partner.unpaid }
|
||||
|
||||
controller do
|
||||
helper 'active_admin/subscription'
|
||||
end
|
||||
|
||||
|
||||
form do |f|
|
||||
f.inputs 'Fields' do
|
||||
f.input(:partner_name, :input_html => { :maxlength => 128 })
|
||||
|
|
@ -61,47 +45,14 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
|||
column 'Code' do |oo|
|
||||
oo.id
|
||||
end
|
||||
column 'Signups' do |oo|
|
||||
column 'Referral Count' do |oo|
|
||||
oo.referral_user_count
|
||||
end
|
||||
column 'JamTracks' do |oo|
|
||||
oo.jamtracks_sold
|
||||
end
|
||||
column 'Subs' do |oo|
|
||||
oo.subscriptions_count
|
||||
end
|
||||
column 'Cum Earnings' do |oo|
|
||||
div do
|
||||
sprintf("Tot $%.2f", oo.cumulative_earnings_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Jam $%.2f", oo.jamtrack_cumulative_earnings_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Sub $%.2f", oo.subscriptions_cumulative_earnings_in_dollars)
|
||||
end
|
||||
end
|
||||
column 'Current Quarter' do |oo|
|
||||
div do
|
||||
sprintf("Tot $%.2f", oo.current_quarter_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Jam $%.2f", oo.jamtrack_current_quarter_in_dollars)
|
||||
end
|
||||
div do
|
||||
sprintf("Sub $%.2f", oo.subscriptions_current_quarter_in_dollars)
|
||||
end
|
||||
column 'Earnings' do |oo|
|
||||
sprintf("$%.2f", oo.cumulative_earnings_in_dollars)
|
||||
end
|
||||
column 'Amount Owed' do |oo|
|
||||
div do
|
||||
sprintf("Tot $%.2f", oo.due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
div do
|
||||
sprintf("Jam $%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
div do
|
||||
sprintf("Sub $%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f)
|
||||
end
|
||||
column 'Pay Actions' do |oo|
|
||||
link_to('Mark Paid', mark_paid_admin_affiliate_path(oo.id), :confirm => "Mark this affiliate as PAID?") if oo.unpaid
|
||||
|
|
@ -120,15 +71,6 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
|
|||
row :address
|
||||
row :tax_identifier
|
||||
row :paypal_id
|
||||
row :venmo_user_id
|
||||
row :jamtracks_sold
|
||||
row :subscriptions_count
|
||||
row :cumulative_earnings_in_dollars
|
||||
row :jamtrack_cumulative_earnings_in_dollars
|
||||
row :subscriptions_cumulative_earnings_in_dollars
|
||||
row :current_quarter_in_dollars
|
||||
row :jamtrack_current_quarter_in_dollars
|
||||
row :subscriptions_current_quarter_in_dollars
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
def get_autocomplete_items(parameters)
|
||||
term = parameters[:term]
|
||||
if term.include?('@')
|
||||
User.select("email, first_name, last_name, id, last_jam_addr").where(["email = ?", term]).limit(5)
|
||||
else
|
||||
User.select("email, first_name, last_name, id, last_jam_addr").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{term}%", "%#{term}%", "%#{term}%"]).limit(40)
|
||||
end
|
||||
User.select("email, first_name, last_name, id, last_jam_addr").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,14 +17,6 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
|||
|
||||
filter :jam_track
|
||||
|
||||
controller do
|
||||
def create
|
||||
jt_params = params[:jam_ruby_jam_track_right]
|
||||
jt_params[:jam_track] =JamRuby::JamTrack.where("id=?", jt_params[:jam_track_id_val]).first # jt_params[:jam_track_id_val]
|
||||
jt_params[:user] = JamRuby::User.where("id=?", jt_params[:user_id_val]).first # jt_params[:user_id_val]
|
||||
create!
|
||||
end
|
||||
end
|
||||
index do
|
||||
actions
|
||||
|
||||
|
|
@ -55,14 +47,9 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
|||
|
||||
form do |f|
|
||||
f.inputs 'New Jam Track Right' do
|
||||
#f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
|
||||
f.input :jam_track_id_val, :required=>true, :as => :hidden
|
||||
|
||||
f.input :jam_track, :required=>true, :as => :autocomplete, :url => autocomplete_jam_track_name_admin_jam_tracks_path, hint: 'Select a jamtrack to give to this user'
|
||||
#f.input :user, :required=>true, collection: User.all, include_blank: false
|
||||
f.input :user_id_val, :required=>true, :as => :hidden
|
||||
f.input :user, :required=>true, :as => :autocomplete, :url => autocomplete_user_email_admin_users_path, hint: 'Give a free jamtrack to this user'
|
||||
f.input :can_download, :required => true, as: :boolean, :input_html => { :checked => 'checked' }
|
||||
f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
|
||||
f.input :user, :required=>true, collection: User.all, include_blank: false
|
||||
f.input :can_download, :required => true, as: :boolean
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
||||
|
||||
collection_action :autocomplete_jam_track_name, :method => :get
|
||||
|
||||
menu :label => 'JamTracks', :parent => 'JamTracks'
|
||||
|
||||
config.sort_order = 'name_asc'
|
||||
|
|
@ -21,19 +19,6 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
|||
|
||||
form :partial => 'form'
|
||||
|
||||
|
||||
controller do
|
||||
|
||||
# this actually searches on first name, last name, and email, because of get_autocomplete_items defined below
|
||||
autocomplete :jam_track, :name, :full => true, :display_value => :autocomplete_display_name
|
||||
|
||||
def get_autocomplete_items(parameters)
|
||||
JamTrack.select("name, original_artist, id").where(["name ILIKE ? OR original_artist ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
index do
|
||||
|
||||
# actions # use this for all view/edit/delete links
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
class Spacer
|
||||
def self.spacer(val, row)
|
||||
|
||||
percentage = ((val * 100) / row.total.to_f).round(1).to_s
|
||||
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
|
||||
end
|
||||
end
|
||||
=begin
|
||||
select
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
|
||||
select first_name, last_name, email
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
AND first_music_session_at is NULL;
|
||||
|
||||
=end
|
||||
|
||||
ActiveAdmin.register_page "Jammers Subscription Cohorts" do
|
||||
menu :parent => 'Reports'
|
||||
|
||||
content :title => "Jammers Subscription Cohorts" do
|
||||
|
||||
filter_type = params[:filter_type] || 'All'
|
||||
filter_campaign = params[:filter_campaign]
|
||||
filter_campaign_id = params[:filter_campaign_id]
|
||||
filter_ad_set = params[:filter_ad_set]
|
||||
filter_ad_name = params[:filter_ad_name]
|
||||
|
||||
campaigns = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_utm_campaign).compact.sort
|
||||
campaign_ids = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_id).compact.sort
|
||||
ad_sets = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_term).compact.sort
|
||||
ad_names = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_content).compact.sort
|
||||
|
||||
div style: "margin-bottom: 20px; padding: 10px; background-color: #f4f4f4; border-radius: 4px;" do
|
||||
form action: admin_jammers_subscription_cohorts_path, method: :get do
|
||||
span "Source: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_type', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: 'All', selected: filter_type == 'All'
|
||||
option "Organic", value: 'Organic', selected: filter_type == 'Organic'
|
||||
option "Advertising", value: 'Advertising', selected: filter_type == 'Advertising'
|
||||
end
|
||||
|
||||
if filter_type == 'Advertising'
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Campaign Name: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_campaign', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_campaign == 'NULL'
|
||||
campaigns.each do |c|
|
||||
option c, value: c, selected: filter_campaign == c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Campaign ID: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_campaign_id', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_campaign_id == 'NULL'
|
||||
campaign_ids.each do |c|
|
||||
option c, value: c, selected: filter_campaign_id == c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Ad Set: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_ad_set', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_ad_set == 'NULL'
|
||||
ad_sets.each do |c|
|
||||
option c, value: c, selected: filter_ad_set == c
|
||||
end
|
||||
end
|
||||
|
||||
div style: "margin-top: 10px;" do
|
||||
span "Ad Name: ", style: "font-weight: bold; margin-right: 5px;"
|
||||
select name: 'filter_ad_name', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
|
||||
option "All", value: ''
|
||||
option "Null", value: 'NULL', selected: filter_ad_name == 'NULL'
|
||||
ad_names.each do |c|
|
||||
option c, value: c, selected: filter_ad_name == c
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
noscript { input type: :submit, value: "Filter" }
|
||||
end
|
||||
end
|
||||
|
||||
h2 "Users Grouped By Month as Paying Subscribers"
|
||||
|
||||
query = User.select(%Q{date_trunc('month', users.created_at) as month,
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed,
|
||||
count(first_played_jamtrack_at) as played_jamtrack
|
||||
})
|
||||
.joins(%Q{LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
j.created_at
|
||||
FROM
|
||||
jam_track_rights as j
|
||||
WHERE
|
||||
j.user_id = users.id
|
||||
ORDER BY
|
||||
j.created_at
|
||||
LIMIT 1 -- Select only that single row
|
||||
) j ON TRUE })
|
||||
|
||||
if filter_type == 'Organic'
|
||||
query = query.where("users.origin_utm_source = 'organic'")
|
||||
elsif filter_type == 'Advertising'
|
||||
query = query.where("origin_utm_medium = 'cpc'")
|
||||
|
||||
if filter_campaign.present?
|
||||
if filter_campaign == 'NULL'
|
||||
query = query.where("users.origin_utm_campaign IS NULL")
|
||||
elsif filter_campaign != 'All'
|
||||
query = query.where("users.origin_utm_campaign = ?", filter_campaign)
|
||||
end
|
||||
end
|
||||
|
||||
if filter_campaign_id.present?
|
||||
if filter_campaign_id == 'NULL'
|
||||
query = query.where("users.origin_id IS NULL")
|
||||
elsif filter_campaign_id != 'All'
|
||||
query = query.where("users.origin_id = ?", filter_campaign_id)
|
||||
end
|
||||
end
|
||||
|
||||
if filter_ad_set.present?
|
||||
if filter_ad_set == 'NULL'
|
||||
query = query.where("users.origin_term IS NULL")
|
||||
elsif filter_ad_set != 'All'
|
||||
query = query.where("users.origin_term = ?", filter_ad_set)
|
||||
end
|
||||
end
|
||||
|
||||
if filter_ad_name.present?
|
||||
if filter_ad_name == 'NULL'
|
||||
query = query.where("users.origin_content IS NULL")
|
||||
elsif filter_ad_name != 'All'
|
||||
query = query.where("users.origin_content = ?", filter_ad_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table_for query.group("date_trunc('month', users.created_at)")
|
||||
.where("j.created_at IS NULL OR (j.created_at - users.created_at) >= INTERVAL '2 hours'")
|
||||
.order("date_trunc('month', users.created_at) DESC") do |row|
|
||||
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
|
||||
column "Total", :total
|
||||
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
|
||||
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
|
||||
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
|
||||
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
|
||||
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
|
||||
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
|
||||
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
|
||||
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
|
||||
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
|
||||
column "Played JT", Proc.new { |user| raw(Spacer.spacer(user.played_jamtrack, user)) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
class Spacer
|
||||
def self.spacer(val, row)
|
||||
|
||||
percentage = ((val * 100) / row.total.to_f).round(1).to_s
|
||||
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
|
||||
end
|
||||
end
|
||||
=begin
|
||||
select
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
|
||||
select first_name, last_name, email
|
||||
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
|
||||
AND first_music_session_at is NULL;
|
||||
|
||||
=end
|
||||
|
||||
ActiveAdmin.register_page "JamTrack Subscription Cohorts" do
|
||||
menu :parent => 'Reports'
|
||||
|
||||
content :title => "JamTrack Subscription Cohorts" do
|
||||
h2 "Users Grouped By Month as Paying Subscribers"
|
||||
table_for User.select(%Q{date_trunc('month', users.created_at) as month,
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(first_subscribed_at) as subscribed,
|
||||
count(first_played_jamtrack_at) as played_jamtrack
|
||||
})
|
||||
.joins(%Q{INNER JOIN LATERAL (
|
||||
SELECT
|
||||
j.created_at
|
||||
FROM
|
||||
jam_track_rights as j
|
||||
WHERE
|
||||
j.user_id = users.id
|
||||
ORDER BY
|
||||
j.created_at
|
||||
LIMIT 1 -- Select only that single row
|
||||
) j ON (j.created_at - users.created_at) < INTERVAL '2 hours' })
|
||||
.group("date_trunc('month', users.created_at)").order("date_trunc('month', users.created_at) DESC") do |row|
|
||||
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
|
||||
column "Total", :total
|
||||
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
|
||||
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
|
||||
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
|
||||
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
|
||||
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
|
||||
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
|
||||
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
|
||||
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
|
||||
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
|
||||
column "Played JT", Proc.new { |user| raw(Spacer.spacer(user.played_jamtrack, user)) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
class Spacer
|
||||
def self.spacer(val, row)
|
||||
|
||||
percentage = ((val * 100) / row.total.to_f).round(1).to_s
|
||||
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
|
||||
end
|
||||
end
|
||||
|
||||
ActiveAdmin.register_page "Subscription Cohorts" do
|
||||
menu :parent => 'Reports'
|
||||
|
||||
|
||||
content :title => "Subscription Cohorts" do
|
||||
h2 "Users Grouped By Month as Paying Subscribers"
|
||||
table_for User.select(%Q{date_trunc('month', created_at) as month,
|
||||
count(id) as total,
|
||||
count(first_downloaded_client_at) as downloaded,
|
||||
count(first_ran_client_at) as ran_client,
|
||||
count(first_certified_gear_at) as ftue,
|
||||
count(first_music_session_at) as any_session,
|
||||
count(first_real_music_session_at) as real_session,
|
||||
count(first_good_music_session_at) as good_session,
|
||||
count(first_invited_at) as invited,
|
||||
count(first_friended_at) as friended,
|
||||
count(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.clear_action_items!
|
||||
config.filters = false
|
||||
config.per_page = 250
|
||||
|
||||
scope("Paid", default: true) { |scope| scope.unscoped.where(:origin_utm_medium => 'cpc').order('created_at desc') }
|
||||
scope("Inorganic Source") { |scope| scope.unscoped.where("origin_utm_source != 'organic' OR origin_utm_source IS NULL").order('created_at desc') }
|
||||
scope("Include Organic") { |scope| scope.unscoped.order('created_at desc') }
|
||||
scope("Most Recent First", default: true) { |scope| scope.unscoped.order('created_at desc')}
|
||||
|
||||
index do
|
||||
column "Email" do |user|
|
||||
user.email
|
||||
end
|
||||
column "Signup (CST)" do |user|
|
||||
user.created_at.in_time_zone("Central Time (US & Canada)")
|
||||
column "Bought TestDrive" do |user|
|
||||
!user.most_recent_test_drive_purchase.nil? ? "Yes" : "No"
|
||||
end
|
||||
column "UTM Source" do |user|
|
||||
user.origin_utm_source
|
||||
|
|
@ -28,23 +25,8 @@ ActiveAdmin.register JamRuby::User, :as => 'UserSource' do
|
|||
column "UTM Campaign" do |user|
|
||||
user.origin_utm_campaign
|
||||
end
|
||||
column "UTM ID" do |user|
|
||||
user.origin_id
|
||||
end
|
||||
column "UTM Term" do |user|
|
||||
user.origin_term
|
||||
end
|
||||
column "UTM Content" do |user|
|
||||
user.origin_content
|
||||
end
|
||||
column "Referrer" do |user|
|
||||
user.origin_referrer
|
||||
end
|
||||
column "FB Click ID" do |user|
|
||||
user.facebook_click_id
|
||||
end
|
||||
column "FB Browser ID" do |user|
|
||||
user.facebook_browser_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,38 +7,6 @@ function intToIP(int) {
|
|||
return part4 + "." + part3 + "." + part2 + "." + part1;
|
||||
}
|
||||
|
||||
function handleJamTrackRightsForm() {
|
||||
var $jamTrackRights = $('form#new_jam_ruby_jam_track_right');
|
||||
var $jamTrack = $jamTrackRights.find('#jam_ruby_jam_track_right_jam_track_id');
|
||||
var $jamTrackVal = $jamTrackRights.find('#jam_ruby_jam_track_right_jam_track_id_val')
|
||||
|
||||
var $user = $jamTrackRights.find('#jam_ruby_jam_track_right_user_id');
|
||||
var $userVal = $jamTrackRights.find('#jam_ruby_jam_track_right_user_id_val');
|
||||
$jamTrack.on('change', function(){
|
||||
console.log("change jam track");
|
||||
});
|
||||
|
||||
/**
|
||||
$user.on('change', function(){
|
||||
console.log("change user");
|
||||
});
|
||||
|
||||
$jamTrack.on('focus', function(){
|
||||
$userVal.val('')
|
||||
});*/
|
||||
|
||||
$jamTrack.bind('railsAutocomplete.select', function(event, data){
|
||||
$jamTrackVal.val('');
|
||||
$jamTrackVal.val(data.item.id);
|
||||
console.log("jam track selected with id " + data.item.id);
|
||||
});
|
||||
|
||||
$user.bind('railsAutocomplete.select', function(event, data){
|
||||
$userVal.val('');
|
||||
$userVal.val(data.item.id);
|
||||
console.log("user selected with id " + data.item.id);
|
||||
});
|
||||
}
|
||||
function handleUserLatencyForm(){
|
||||
var $userLatenciesForm = $('form#user_latencies_form');
|
||||
var $latenciesMyUser = $userLatenciesForm.find('#latencies_my_user');
|
||||
|
|
@ -106,5 +74,4 @@ function handleLatencyRecommendationForm(){
|
|||
$(document).ready(function() {
|
||||
handleUserLatencyForm();
|
||||
handleLatencyRecommendationForm();
|
||||
handleJamTrackRightsForm();
|
||||
});
|
||||
|
|
@ -2,97 +2,55 @@ class ArsesController < ApplicationController
|
|||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
if params[:code] != Rails.application.config.data_dump_code
|
||||
render :json => {error: "Unauthorized"}, :status => 401
|
||||
return
|
||||
end
|
||||
|
||||
@arses = JamRuby::Ars.all
|
||||
render :json => @arses
|
||||
end
|
||||
|
||||
def update
|
||||
if params[:code] != Rails.application.config.data_dump_code
|
||||
render :json => {error: "Unauthorized"}, :status => 401
|
||||
return
|
||||
end
|
||||
|
||||
begin
|
||||
# Primary ID lookup
|
||||
@ars = JamRuby::Ars.find_by_id(params[:id])
|
||||
|
||||
# Explicit secondary lookups if primary ID fails
|
||||
@ars ||= JamRuby::Ars.find_by_id_int(params[:id_int]) if params[:id_int]
|
||||
@ars ||= JamRuby::Ars.find_by_name(params[:name]) if params[:name]
|
||||
|
||||
if @ars.nil?
|
||||
render :json => {error: "Not Found"}, :status => 404
|
||||
return
|
||||
end
|
||||
|
||||
allowed = [:password, :username, :active, :beta, :name, :provider, :id_int, :ip, :port, :continent, :country, :city, :subdivision, :latitude, :longitude]
|
||||
|
||||
update_hash = {}
|
||||
allowed.each do |attr|
|
||||
update_hash[attr] = params[attr] if params.has_key?(attr)
|
||||
end
|
||||
|
||||
if @ars.update_attributes(update_hash, as: :admin)
|
||||
render :json => @ars, :status => :ok
|
||||
else
|
||||
render :json => @ars.errors, :status => :unprocessable_entity
|
||||
end
|
||||
rescue => e
|
||||
render :json => {error: e.message, backtrace: e.backtrace.first(5)}, :status => 500
|
||||
end
|
||||
end
|
||||
|
||||
# create or update a client_artifact row
|
||||
def get_or_create
|
||||
begin
|
||||
name = params[:name]
|
||||
provider = params[:provider]
|
||||
active = params[:active]
|
||||
beta = params.has_key?(:beta) ? params[:beta] : true
|
||||
ip = params[:ip]
|
||||
username = params[:username]
|
||||
password = params[:password]
|
||||
topology = params[:topology]
|
||||
ars_id = params[:ars_id]
|
||||
name = params[:name]
|
||||
provider = params[:provider]
|
||||
active = params[:active]
|
||||
ip = params[:ip]
|
||||
username = params[:username]
|
||||
password = params[:password]
|
||||
topology = params[:topology]
|
||||
ars_id = params[:ars_id]
|
||||
puts "TOPOLOGY #{topology}"
|
||||
|
||||
# Explicit field-based lookups
|
||||
ars = nil
|
||||
ars = JamRuby::Ars.find_by_id_int(ars_id) if ars_id
|
||||
ars ||= JamRuby::Ars.find_by_name(name) if name
|
||||
|
||||
if ars.nil?
|
||||
ars = JamRuby::Ars.new
|
||||
ars.name = name
|
||||
end
|
||||
|
||||
ars.id_int = ars_id if !ars_id.nil?
|
||||
ars.provider = provider
|
||||
ars.active = active
|
||||
ars.beta = params[:beta]
|
||||
ars.beta = beta
|
||||
ars.ip = ip
|
||||
ars.password = password
|
||||
ars.username = username
|
||||
if topology
|
||||
ars.city = topology['city']
|
||||
ars.country = topology['country']
|
||||
ars.continent = topology['continent']
|
||||
ars.latitude = topology['latitude']
|
||||
ars.longitude = topology['longitude']
|
||||
ars.subdivision = topology['subdivision']
|
||||
end
|
||||
ars.save!
|
||||
|
||||
@ars = ars
|
||||
render :json => {id_int: @ars.id_int, id: @ars.id, name: @ars.name, provider: @ars.provider, active: @ars.active, beta: @ars.beta, ip: @ars.ip}, :status => :ok
|
||||
rescue => e
|
||||
render :json => {error: e.message, backtrace: e.backtrace.first(5)}, :status => 500
|
||||
if ars_id
|
||||
ars = Ars.find_by_id_int(ars_id)
|
||||
end
|
||||
if ars.nil?
|
||||
ars = Ars.new
|
||||
ars.name = name
|
||||
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
|
||||
|
|
|
|||
|
|
@ -112,19 +112,6 @@ class Cohort < ActiveRecord::Base
|
|||
def self.cohort_users(cohort)
|
||||
User.where(created_at: cohort.group_start..cohort.group_end)
|
||||
end
|
||||
=begin
|
||||
SELECT played.user_id FROM
|
||||
(SELECT user_id, COUNT(*) cnt FROM music_sessions_user_history msuh1
|
||||
WHERE
|
||||
msuh1.created_at >= '2024-11-01' AND
|
||||
msuh1.created_at <= '202' AND
|
||||
EXTRACT(EPOCH FROM (msuh1.session_removed_at - msuh1.created_at)) >= 900 AND
|
||||
(SELECT COUNT(*) FROM music_sessions_user_history msuh2
|
||||
WHERE msuh1.music_session_id = msuh2.music_session_id
|
||||
) > 1
|
||||
GROUP BY user_id
|
||||
) played
|
||||
=end
|
||||
|
||||
def _played_online_subquery(constraint)
|
||||
where = if constraint.is_a?(Range)
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
BUNDLE_GEMFILE=Gemfile.alt RAILS_ENV=development LOCAL_DEV=1 MODERN_OS=1 JAM_RUBY_VERSION=2.4.1 bundle _1.17.3_ exec rails server -b 0.0.0.0 -p 3333
|
||||
|
|
@ -131,7 +131,7 @@ module JamAdmin
|
|||
config.email_smtp_starttls_auto = true
|
||||
|
||||
config.verify_email_enabled = false
|
||||
config.musician_count = '300,000+'
|
||||
config.musician_count = '200,000+'
|
||||
config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398'
|
||||
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
class JamRuby::JamTrackRight
|
||||
attr_accessible :jam_track, :user, :jam_track_id_val, :user_id_val, as: :admin
|
||||
|
||||
def jam_track_id_val
|
||||
|
||||
end
|
||||
|
||||
def jam_track_id_val=(val)
|
||||
end
|
||||
|
||||
def user_id_val
|
||||
|
||||
end
|
||||
|
||||
def user_id_val=(val)
|
||||
end
|
||||
end
|
||||
|
|
@ -3,8 +3,4 @@ class JamRuby::JamTrack
|
|||
# add a custom validation
|
||||
|
||||
|
||||
def autocomplete_display_name
|
||||
"#{original_artist} - #{name}"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,10 +20,6 @@ JamAdmin::Application.routes.draw do
|
|||
post :user_latencies, on: :collection
|
||||
post :user_latency_recommendation, on: :collection
|
||||
end
|
||||
|
||||
resources :jam_tracks do
|
||||
get :autocomplete_jam_track_name, :on => :collection
|
||||
end
|
||||
end
|
||||
|
||||
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/arses/register' => 'arses#get_or_create', :via => :post
|
||||
match '/api/arses' => 'arses#index', :via => :get
|
||||
match '/api/arses/:id' => 'arses#update', :via => :post
|
||||
|
||||
mount Resque::Server.new, :at => "/resque"
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
# trigger build
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
image: node:14.21.3
|
||||
image: node:14.17.1
|
||||
|
||||
pipelines:
|
||||
branches:
|
||||
|
|
@ -6,93 +6,33 @@ pipelines:
|
|||
- step:
|
||||
name: Build Staging
|
||||
script:
|
||||
- pushd jam-ui
|
||||
- npm install
|
||||
- popd
|
||||
- pushd jam-ui/cicd
|
||||
- npm install
|
||||
- NODE_ENV=production PUBLIC_URL=https://staging.jamkazam.com REACT_APP_ORIGIN=staging.jamkazam.com REACT_APP_BASE_URL=https://staging.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT ENVIRONMENT=staging ./generate.sh
|
||||
- popd
|
||||
- cd jam-ui
|
||||
- NODE_ENV=production CI=false PUBLIC_URL=https://staging.jamkazam.com REACT_APP_ORIGIN=staging.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com REACT_APP_BASE_URL=https://staging.jamkazam.com REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT npm run build
|
||||
- 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:
|
||||
- jam-ui/build/**
|
||||
- step:
|
||||
name: Deploy to staging - SPA
|
||||
name: Deploy to staging
|
||||
deployment: staging
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
- pipe: atlassian/aws-s3-deploy:1.1.0
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/stg"
|
||||
LOCAL_PATH: "jam-ui/build"
|
||||
EXTRA_ARGS: "--exclude=*backing-tracks/*"
|
||||
- step:
|
||||
name: Deploy to staging - backing-tracks
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/stg/backing-tracks"
|
||||
LOCAL_PATH: "jam-ui/build/backing-tracks"
|
||||
EXTRA_ARGS: "--exclude=*.js --content-type text/html"
|
||||
- step:
|
||||
name: Deploy to staging - backing-tracks js
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/stg/js"
|
||||
LOCAL_PATH: "jam-ui/build/js"
|
||||
EXTRA_ARGS: "--content-type text/javascript"
|
||||
# - step:
|
||||
# name: Deploy to staging - invalidate cloudfront distribution
|
||||
# deployment: staging
|
||||
# script:
|
||||
# - pipe: atlassian/aws-cloudfront-invalidate:0.10.1
|
||||
# variables:
|
||||
# DISTRIBUTION_ID: "E2AQIC9RSON94Q" # ESQDIABYLT0RV
|
||||
custom:
|
||||
build-and-deploy-to-production:
|
||||
- step:
|
||||
name: Build Production
|
||||
script:
|
||||
- pushd jam-ui
|
||||
- npm install
|
||||
- popd
|
||||
- pushd jam-ui/cicd
|
||||
- npm install
|
||||
- NODE_ENV=production ENVIRONMENT=production PUBLIC_URL=https://www.jamkazam.com REACT_APP_ORIGIN=jamkazam.com REACT_APP_BASE_URL=https://www.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com REACT_APP_API_BASE_URL=https://www.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB ./generate.sh
|
||||
- popd
|
||||
- cd jam-ui
|
||||
- NODE_ENV=production CI=false PUBLIC_URL=https://www.jamkazam.com REACT_APP_ORIGIN=jamkazam.com REACT_APP_BASE_URL=https://www.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com REACT_APP_API_BASE_URL=https://www.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB npm run build
|
||||
|
||||
- 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:
|
||||
- jam-ui/build/**
|
||||
|
||||
- step:
|
||||
name: Deploy to production - SPA
|
||||
name: Deploy to production
|
||||
deployment: production
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
- pipe: atlassian/aws-s3-deploy:1.1.0
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/prd"
|
||||
LOCAL_PATH: "jam-ui/build"
|
||||
EXTRA_ARGS: "--exclude=*backing-tracks/*"
|
||||
- step:
|
||||
name: Deploy to production - backing-tracks
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/prd/backing-tracks"
|
||||
LOCAL_PATH: "jam-ui/build/backing-tracks"
|
||||
EXTRA_ARGS: "--exclude=*.js --content-type text/html"
|
||||
- step:
|
||||
name: Deploy to production - backing-tracks js
|
||||
script:
|
||||
- pipe: atlassian/aws-s3-deploy:1.6.2
|
||||
variables:
|
||||
S3_BUCKET: "jamkazam-ui/prd/js"
|
||||
LOCAL_PATH: "jam-ui/build/js"
|
||||
EXTRA_ARGS: "--content-type text/javascript"
|
||||
#- step:
|
||||
# name: Deploy to production - invalidate cloudfront distribution
|
||||
# deployment: production
|
||||
# script:
|
||||
# - pipe: atlassian/aws-cloudfront-invalidate:0.10.1
|
||||
# variables:
|
||||
# DISTRIBUTION_ID: "ESQDIABYLT0RV"
|
||||
LOCAL_PATH: "jam-ui/build"
|
||||
|
|
@ -1,16 +1,8 @@
|
|||
HOST=beta.jamkazam.local
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=jamkazam.local
|
||||
REACT_APP_BASE_URL=http://beta.jamkazam.local:4000
|
||||
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
|
||||
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
||||
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
||||
REACT_APP_BITBUCKET_COMMIT=dev
|
||||
REACT_APP_ENV=development
|
||||
REACT_APP_RECAPTCHA_ENABLED=false
|
||||
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-MC9BTWXWY4
|
||||
PUBLIC_URL=
|
||||
REACT_APP_COOKIE_DOMAIN=.jamkazam.local
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-hvDV1xQxDw0HPaaRFP4KNE
|
||||
REACT_APP_BRAINTREE_TOKEN=sandbox_pgjp8dvs_5v5rwm94m2vrfbms
|
||||
REACT_APP_ENV=development
|
||||
|
|
@ -1,13 +1,8 @@
|
|||
HOST=beta.jamkazam.local
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=jamkazam.local
|
||||
REACT_APP_BASE_URL=http://beta.jamkazam.local:4000
|
||||
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
|
||||
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
|
||||
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
|
||||
REACT_APP_BITBUCKET_COMMIT=dev
|
||||
REACT_APP_ENV=development
|
||||
REACT_APP_COOKIE_DOMAIN=.jamkazam.com
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-MC9BTWXWY4
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=
|
||||
REACT_APP_BRAINTREE_TOKEN=
|
||||
REACT_APP_ENV=development
|
||||
|
|
@ -1,13 +1,6 @@
|
|||
HOST=beta.jamkazam.com
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=jamkazam.com
|
||||
REACT_APP_BASE_URL=https://www.jamkazam.com
|
||||
REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com
|
||||
REACT_APP_API_BASE_URL=https://www.jamkazam.com/api
|
||||
REACT_APP_ENV=production
|
||||
REACT_APP_RECAPTCHA_ENABLED=true
|
||||
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
|
||||
REACT_APP_COOKIE_DOMAIN=.jamkazam.com
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-hvDV1xQxDw0HPaaRFP4KNE
|
||||
REACT_APP_BRAINTREE_TOKEN=production_hc7z69yq_pwwc6zm3d478kfrh
|
||||
REACT_APP_ENV=production
|
||||
|
|
@ -1,13 +1,6 @@
|
|||
HOST=beta.staging.jamkazam.com
|
||||
PORT=4000
|
||||
REACT_APP_ORIGIN=staging.jamkazam.com
|
||||
REACT_APP_BASE_URL=https://staging.jamkazam.com
|
||||
REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com
|
||||
REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api
|
||||
REACT_APP_ENV=staging
|
||||
REACT_APP_RECAPTCHA_ENABLED=false
|
||||
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
|
||||
REACT_APP_COOKIE_DOMAIN=.staging.jamkazam.com
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT
|
||||
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-AjUHUfcLtIsPdtetD4mj2x
|
||||
REACT_APP_BRAINTREE_TOKEN=sandbox_pgjp8dvs_5v5rwm94m2vrfbms
|
||||
REACT_APP_ENV=staging
|
||||
|
|
@ -3,6 +3,6 @@
|
|||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"react/no-unescaped-entities": 0
|
||||
"react/no-unescaped-entities": false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,4 @@ yarn-error.log*
|
|||
/test-results
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
|
||||
/public/backing-tracks
|
||||
/public/js
|
||||
/cypress/screenshots/
|
||||
|
|
@ -1,14 +1,5 @@
|
|||
# JamKazam new react frontend UI/UX
|
||||
|
||||
`jam-ui` is a react app created using `create-react-app` utility. to run the app on your development environment you need to `cd jam-ui` and run `npm run start`
|
||||
|
||||
The changes to the source files are auto-loaded but sometimes you might need to force close it by crtl+c and then start manually.
|
||||
|
||||
The application files goes under `src` and the react components are placed under `src/components` directory. We have a convention of naming the files using JK prefix in the filename. For example `JKMusicSessions`.
|
||||
|
||||
The routes are defined in `jam-ui/src/components/dashboard/JKDashboardMain.js`
|
||||
|
||||
|
||||
## Running react app
|
||||
|
||||
In production this React app is supposed to run on beta.jamkazam.com subdomain which is same origin domain to the production Rails app (www.jamkazam.com). This way we utilize same session based user authentication of Rails web app for authenticating users. (It looks for remember_token session cookie in headers and if it is not availale redirect the user to Rails web app sign in page)
|
||||
|
|
@ -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.
|
||||
|
||||
## 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
|
||||
|
||||
|
|
@ -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,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,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');
|
||||
});
|
||||
});
|
||||
|
|
@ -21,7 +21,7 @@ describe('Affiliate Earnings', () => {
|
|||
}).as('fetchAllEarnings');
|
||||
cy.visit('/affiliate/earnings');
|
||||
cy.wait('@fetchAllEarnings');
|
||||
cy.contains('There is no earnings data yet ');
|
||||
cy.contains('No Records!');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ describe('Affiliate Earnings', () => {
|
|||
cy.wait('@fetchAllEarnings');
|
||||
cy.get('[data-testid=affiliateEarningsList] tbody tr:first-child td')
|
||||
.eq(0)
|
||||
.should('have.text', 'September 2021');
|
||||
.should('have.text', 'September - 2021');
|
||||
cy.get('[data-testid=affiliateEarningsList] tbody tr:first-child td')
|
||||
.eq(1)
|
||||
.should('have.text', 'Silver - 2');
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ describe('affiliate signups', () => {
|
|||
}).as('fetchAllSignups');
|
||||
cy.visit('/affiliate/signups');
|
||||
cy.wait('@fetchAllSignups');
|
||||
cy.contains('There is no signup data yet ');
|
||||
cy.contains('No Records!');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
it('redirects to login page', () => {
|
||||
cy.clearCookie('remeber_token')
|
||||
cy.visit('/')
|
||||
cy.url().should('include', '/auth/login')
|
||||
cy.contains('Sign In')
|
||||
cy.visit('/friends')
|
||||
cy.url().should('include', '/authentication/basic/login')
|
||||
cy.contains('Sign in')
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ describe('Login page', () => {
|
|||
})
|
||||
|
||||
it('validate login form', () => {
|
||||
cy.visit('/auth/login')
|
||||
cy.visit('/authentication/basic/login')
|
||||
cy.reload()
|
||||
cy.get('[data-testid=submit]').should('be.disabled')
|
||||
cy.get('[data-testid=email]').type('invalid-email-format@example')
|
||||
|
|
@ -54,7 +54,7 @@ describe('Login page', () => {
|
|||
})
|
||||
|
||||
it('submit login form with invalid credentials', () => {
|
||||
cy.visit('/auth/login')
|
||||
cy.visit('/authentication/basic/login')
|
||||
cy.reload()
|
||||
cy.get('[data-testid=email]').type('peter@example.com')
|
||||
cy.get('[data-testid=password]').type('wrong')
|
||||
|
|
@ -63,7 +63,7 @@ describe('Login page', () => {
|
|||
})
|
||||
|
||||
it('submits login form', () => {
|
||||
cy.visit('/auth/login')
|
||||
cy.visit('/authentication/basic/login')
|
||||
submitLogin()
|
||||
cy.url().should('eq', Cypress.config().baseUrl + '/') // tests won't fail in case the port changes
|
||||
//cy.contains('Signed in as peter@example.com')
|
||||
|
|
@ -73,7 +73,7 @@ describe('Login page', () => {
|
|||
|
||||
it('redirect to requested page', () => {
|
||||
cy.visit('/friends')
|
||||
cy.url().should('include', '/auth/login')
|
||||
cy.url().should('include', '/authentication/basic/login')
|
||||
cy.reload()
|
||||
submitLogin()
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,7 @@ describe('Friends page without data', () => {
|
|||
}).as("getPeople_empty");
|
||||
});
|
||||
|
||||
//from_location checkbox is hidden for now. so we skip this test for now
|
||||
it.skip('from_location is unchecked', () => {
|
||||
it('from_location is unchecked', () => {
|
||||
cy.visit('/friends');
|
||||
|
||||
//default api call with from_location parameter turned off
|
||||
|
|
@ -100,10 +99,6 @@ describe('Friends page with data', () => {
|
|||
cy.intercept('POST', /\S+\/filter\?offset=10/, { fixture: 'people_page2' }).as('getPeople_page2');
|
||||
cy.intercept('POST', /\S+\/filter\?offset=20/, { fixture: 'people_page3' }).as('getPeople_page3');
|
||||
cy.intercept('GET', /\S+\/profile/, { fixture: 'person' });
|
||||
cy.intercept('GET', /\S+\/my_notifications\S+/, {
|
||||
statusCode: 200,
|
||||
body: []
|
||||
});
|
||||
});
|
||||
|
||||
describe('listing users', () => {
|
||||
|
|
@ -121,6 +116,7 @@ describe('Friends page with data', () => {
|
|||
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');
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const closeSidePanel = () => {
|
|||
cy.get('[data-testid=profileSidePanel] .modal-header button.close').click();
|
||||
};
|
||||
|
||||
describe('Friends page without data', () => {
|
||||
describe.only('Friends page without data', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
// cy.intercept('POST', /\S+\/filter/, {
|
||||
|
|
|
|||
|
|
@ -1,31 +1,23 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
import makeFakeUser from '../../factories/user';
|
||||
|
||||
describe('Unsubscribe from email link', () => {
|
||||
beforeEach(() => {
|
||||
// cy.intercept('POST', /\S+\/unsubscribe_user_match\/\S+/, { statusCode: 200, body: { ok: true } });
|
||||
const currentUser = makeFakeUser({
|
||||
email: 'sam@example.com'
|
||||
});
|
||||
cy.stubAuthenticate({ ...currentUser });
|
||||
cy.intercept('POST', /\S+\/unsubscribe\/\S+/, { statusCode: 200, body: { ok: true } });
|
||||
beforeEach(() =>{
|
||||
cy.intercept('POST', /\S+\/unsubscribe_user_match\/\S+/, { statusCode: 200, body: { ok: true } });
|
||||
})
|
||||
|
||||
it("redirect to home page if tok is not provided", () => {
|
||||
cy.visit('/unsubscribe');
|
||||
cy.location('pathname').should('eq', '/errors/404');
|
||||
cy.location('pathname').should('eq', '/');
|
||||
});
|
||||
|
||||
it("show unsubscribed message", () => {
|
||||
cy.visit('/unsubscribe/123');
|
||||
// cy.location('search')
|
||||
// .should('equal', '?tok=123')
|
||||
// .then((s) => new URLSearchParams(s))
|
||||
// .invoke('get', 'tok')
|
||||
// .should('equal', '123')
|
||||
cy.contains("You have successfully unsubscribed from JamKazam emails.").should('be.visible');
|
||||
cy.contains("Loading...").should('not.exist');
|
||||
it.only("show unsubscribed message", () => {
|
||||
cy.visit('/unsubscribe?tok=123');
|
||||
cy.location('search')
|
||||
.should('equal', '?tok=123')
|
||||
.then((s) => new URLSearchParams(s))
|
||||
.invoke('get', 'tok')
|
||||
.should('equal', '123')
|
||||
cy.contains("successfully unsubscribed")
|
||||
});
|
||||
|
||||
})
|
||||
|
|
@ -32,80 +32,46 @@ describe('JamTracks Page', () => {
|
|||
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
|
||||
}
|
||||
}
|
||||
body: { success: true }
|
||||
}).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"');
|
||||
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.get('[data-testid=jamtracks-table] tbody tr').eq(2).find('.purchase-button-col button').should('contain', 'Add to Cart').click();
|
||||
cy.wait('@addJamTrackToCart');
|
||||
cy.location('pathname').should('eq', '/shopping-cart')
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ describe('JamTracks 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');
|
||||
cy.url().should('include', '/jamtracks/1');
|
||||
});
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ describe('Top Navigation', () => {
|
|||
|
||||
const showProfileDropdown = () => {
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('exist');
|
||||
cy.contains('Peter Pan').should('exist');
|
||||
//cy.contains("My Profile").should('exist')
|
||||
cy.contains('Sign Out').should('exist');
|
||||
};
|
||||
|
||||
|
|
@ -19,13 +21,14 @@ describe('Top Navigation', () => {
|
|||
it('shows homepage', () => {
|
||||
cy.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
cy.contains('Sign in').should('exist');
|
||||
cy.contains('Home').should('exist');
|
||||
showSubscribeToUpdates();
|
||||
});
|
||||
|
||||
it('not allowed to protected page', () => {
|
||||
cy.visit('/friends');
|
||||
cy.wait('@getAppFeatures');
|
||||
cy.url().should('include', '/auth/login');
|
||||
cy.url().should('include', '/authentication/basic/login');
|
||||
cy.contains('Sign in');
|
||||
cy.get('button').should('have.text', 'Sign in');
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist');
|
||||
|
|
@ -46,20 +49,21 @@ describe('Top Navigation', () => {
|
|||
|
||||
it('sign out', () => {
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]')
|
||||
.contains('Peter Pan')
|
||||
.click();
|
||||
cy.stubUnauthenticate();
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]')
|
||||
.contains('Sign Out')
|
||||
.click();
|
||||
cy.get('[data-testid=navbarTopProfileDropdown]').should('not.exist');
|
||||
cy.contains('Sign in');
|
||||
cy.contains('Home');
|
||||
});
|
||||
});
|
||||
|
||||
describe('header notifications', () => {
|
||||
beforeEach(() => {
|
||||
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.visit('/');
|
||||
cy.wait('@getAppFeatures');
|
||||
|
|
@ -67,8 +71,7 @@ describe('Top Navigation', () => {
|
|||
|
||||
it('shows notifications', () => {
|
||||
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]')
|
||||
|
|
@ -78,7 +81,7 @@ describe('Top Navigation', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe.skip('locale switch', () => {
|
||||
describe('locale switch', () => {
|
||||
beforeEach(() => {
|
||||
cy.stubAuthenticate();
|
||||
cy.visit('/');
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@ describe('Browse sessions', () => {
|
|||
});
|
||||
|
||||
it('alerts when there is no records', () => {
|
||||
cy.contains('There are no public, open sessions currently available for you to join');
|
||||
cy.contains('create a session').click();
|
||||
cy.url().should('include', '/sessions/new');
|
||||
cy.contains('No Records!');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -263,7 +261,7 @@ describe('Browse sessions', () => {
|
|||
}
|
||||
]
|
||||
});
|
||||
//console.log('_DEBUG_ session', session);
|
||||
console.log('_DEBUG_ session', session);
|
||||
cy.intercept('GET', /\S+\/api\/sessions/, [session]);
|
||||
cy.visit('/sessions');
|
||||
cy.get('[data-testid=sessionsListTable] tbody tr').contains('YOU HAVE A FRIEND IN THIS SESSION');
|
||||
|
|
|
|||
|
|
@ -1,81 +1,74 @@
|
|||
{
|
||||
"next": null,
|
||||
"unread_total": 3,
|
||||
"notifications": [
|
||||
{
|
||||
"description": "TEXT_MESSAGE",
|
||||
"source_user_id": "27bd4a30-d1b8-4eea-8454-01a104d59381",
|
||||
"target_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
||||
"session_id": null,
|
||||
"recording_id": null,
|
||||
"invitation_id": null,
|
||||
"join_request_id": null,
|
||||
"friend_request_id": null,
|
||||
"band_id": null,
|
||||
"band_invitation_id": null,
|
||||
"formatted_msg": "TEXT_MESSAGE",
|
||||
"message": "Hello",
|
||||
"created_at": "2021-10-07T00:09:57.704Z",
|
||||
"lesson_session_id": null,
|
||||
"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
|
||||
[
|
||||
{
|
||||
"description": "TEXT_MESSAGE",
|
||||
"source_user_id": "27bd4a30-d1b8-4eea-8454-01a104d59381",
|
||||
"target_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
||||
"session_id": null,
|
||||
"recording_id": null,
|
||||
"invitation_id": null,
|
||||
"join_request_id": null,
|
||||
"friend_request_id": null,
|
||||
"band_id": null,
|
||||
"band_invitation_id": null,
|
||||
"formatted_msg": "TEXT_MESSAGE",
|
||||
"message": "Hello",
|
||||
"created_at": "2021-10-07T00:09:57.704Z",
|
||||
"lesson_session_id": null,
|
||||
"purpose": null,
|
||||
"source_user": {
|
||||
"name": "Nuwan Chaturanga"
|
||||
},
|
||||
{
|
||||
"description": "FRIEND_REQUEST",
|
||||
"source_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
||||
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
||||
"session_id": null,
|
||||
"recording_id": null,
|
||||
"invitation_id": null,
|
||||
"join_request_id": null,
|
||||
"friend_request_id": "7c842904-24f5-4515-8886-0c3d25ee641b",
|
||||
"band_id": null,
|
||||
"band_invitation_id": null,
|
||||
"formatted_msg": "Seth Call has sent you a friend request.",
|
||||
"message": null,
|
||||
"created_at": "2021-10-15T05:36:48.527Z",
|
||||
"lesson_session_id": null,
|
||||
"purpose": null,
|
||||
"source_user": {
|
||||
"name": "Seth Call"
|
||||
},
|
||||
"notification_id": "3364b5f1-8946-46a3-b635-86d89d237849",
|
||||
"fan_access": null,
|
||||
"musician_access": null,
|
||||
"approval_required": null,
|
||||
"read_at": null
|
||||
"notification_id": "63fcd878-9a22-4419-9cee-8a51a615da97",
|
||||
"fan_access": null,
|
||||
"musician_access": null,
|
||||
"approval_required": null
|
||||
},
|
||||
{
|
||||
"description": "FRIEND_REQUEST",
|
||||
"source_user_id": "a09f9a7e-afb7-489d-870d-e13a336e0b97",
|
||||
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
||||
"session_id": null,
|
||||
"recording_id": null,
|
||||
"invitation_id": null,
|
||||
"join_request_id": null,
|
||||
"friend_request_id": "7c842904-24f5-4515-8886-0c3d25ee641b",
|
||||
"band_id": null,
|
||||
"band_invitation_id": null,
|
||||
"formatted_msg": "Seth Call has sent you a friend request.",
|
||||
"message": null,
|
||||
"created_at": "2021-10-15T05:36:48.527Z",
|
||||
"lesson_session_id": null,
|
||||
"purpose": null,
|
||||
"source_user": {
|
||||
"name": "Seth Call"
|
||||
},
|
||||
{
|
||||
"description": "FRIEND_REQUEST_ACCEPTED",
|
||||
"source_user_id": "29becbf4-8be5-4078-9405-0edadc9fa42d",
|
||||
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
||||
"session_id": null,
|
||||
"recording_id": null,
|
||||
"invitation_id": null,
|
||||
"join_request_id": null,
|
||||
"friend_request_id": null,
|
||||
"band_id": null,
|
||||
"band_invitation_id": null,
|
||||
"formatted_msg": "Peter Walker has accepted your friend request.",
|
||||
"message": null,
|
||||
"created_at": "2021-10-05T12:38:53.134Z",
|
||||
"lesson_session_id": null,
|
||||
"purpose": null,
|
||||
"source_user": {
|
||||
"name": "Peter Walker"
|
||||
},
|
||||
"notification_id": "bb9269f3-721c-48cd-9bf6-bcff72877198",
|
||||
"fan_access": null,
|
||||
"musician_access": null,
|
||||
"approval_required": null,
|
||||
"read_at": null
|
||||
}
|
||||
]
|
||||
}
|
||||
"notification_id": "3364b5f1-8946-46a3-b635-86d89d237849",
|
||||
"fan_access": null,
|
||||
"musician_access": null,
|
||||
"approval_required": null
|
||||
},
|
||||
{
|
||||
"description": "FRIEND_REQUEST_ACCEPTED",
|
||||
"source_user_id": "29becbf4-8be5-4078-9405-0edadc9fa42d",
|
||||
"target_user_id": "b1ddadd0-0263-47c4-bf91-e7767f386970",
|
||||
"session_id": null,
|
||||
"recording_id": null,
|
||||
"invitation_id": null,
|
||||
"join_request_id": null,
|
||||
"friend_request_id": null,
|
||||
"band_id": null,
|
||||
"band_invitation_id": null,
|
||||
"formatted_msg": "Peter Walker has accepted your friend request.",
|
||||
"message": null,
|
||||
"created_at": "2021-10-05T12:38:53.134Z",
|
||||
"lesson_session_id": null,
|
||||
"purpose": null,
|
||||
"source_user": {
|
||||
"name": "Peter Walker"
|
||||
},
|
||||
"notification_id": "bb9269f3-721c-48cd-9bf6-bcff72877198",
|
||||
"fan_access": null,
|
||||
"musician_access": null,
|
||||
"approval_required": null
|
||||
}
|
||||
]
|
||||
|
|
@ -27,26 +27,6 @@ beforeEach(() => {
|
|||
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
|
||||
.src('src/assets/scss/theme.scss')
|
||||
.src('src/assets/scss/*.scss')
|
||||
.pipe(plumber())
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(
|
||||
|
|
@ -49,7 +49,7 @@ gulp.task('scss:dark', () =>
|
|||
|
||||
gulp.task('scss:rtl', () =>
|
||||
gulp
|
||||
.src('src/assets/scss/theme.scss')
|
||||
.src('src/assets/scss/*.scss')
|
||||
.pipe(plumber())
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"private": true,
|
||||
"dependencies": {
|
||||
"@farfetch/react-context-responsive": "^1.5.0",
|
||||
"@fingerprintjs/fingerprintjs": "^4.6.0",
|
||||
"@fingerprintjs/fingerprintjs": "^4.4.3",
|
||||
"@fortawesome/fontawesome-free": "^5.15.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.30",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.14.0",
|
||||
|
|
@ -32,7 +32,6 @@
|
|||
"element-resize-event": "^3.0.3",
|
||||
"emoji-mart": "^3.0.0",
|
||||
"faker": "^5.5.3",
|
||||
"filestack-js": "^3.32.3",
|
||||
"fuse.js": "^6.4.3",
|
||||
"google-maps-react": "^2.0.6",
|
||||
"howler": "^2.2.4",
|
||||
|
|
@ -61,8 +60,6 @@
|
|||
"react-dropzone": "^10.2.2",
|
||||
"react-es6-progressbar.js": "^1.1.0",
|
||||
"react-flatpickr": "^3.10.6",
|
||||
"react-ga4": "^2.1.0",
|
||||
"react-google-recaptcha": "^3.1.0",
|
||||
"react-hook-form": "^7.11.1",
|
||||
"react-https-redirect": "^1.1.0",
|
||||
"react-i18next": "^11.12.0",
|
||||
|
|
@ -107,7 +104,6 @@
|
|||
"eslint-config-prettier": "^4.2.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"eslint-plugin-react": "^7.20.6",
|
||||
"eslint-plugin-react-hooks": "^1.7.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-autoprefixer": "^6.1.0",
|
||||
"gulp-clean-css": "^4.3.0",
|
||||
|
|
|
|||
|
|
@ -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 |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
|
@ -1,43 +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 499 146" 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-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
|
||||
<g>
|
||||
<g transform="matrix(1,0,0,1,-57.9807,-32.8429)">
|
||||
<path d="M556.58,69.309L556.58,142.277C556.58,162.413 540.232,178.761 520.096,178.761L94.466,178.761C74.33,178.761 57.982,162.413 57.982,142.277L57.982,69.309C57.982,49.173 74.33,32.825 94.466,32.825L520.096,32.825C540.232,32.825 556.58,49.173 556.58,69.309Z" style="fill:rgb(64,124,222);stroke:rgb(64,124,222);stroke-width:1px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.735399,0,0,0.685712,16.2125,4.37876)">
|
||||
<use xlink:href="#_Image1" x="0" y="0" width="200px" height="200px"/>
|
||||
</g>
|
||||
<g transform="matrix(0.835193,0,0,0.769777,7.35556,11.1156)">
|
||||
<g transform="matrix(0,45.5199,41.8804,0,154.724,117.573)">
|
||||
<clipPath id="_clip2">
|
||||
<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" clip-rule="nonzero"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#_clip2)">
|
||||
<g transform="matrix(-0,0.0285892,0.0285387,-0,-2.90011,-3.90471)">
|
||||
<use xlink:href="#_Image3" x="118.559" y="102.621" width="37px" height="37px"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(0.0344151,0,0,0.0374059,147.879,151.575)">
|
||||
<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(0.0344151,0,0,0.0374059,166.511,149.078)">
|
||||
<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(0.0344151,0,0,0.0374059,143.804,133.272)">
|
||||
<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>
|
||||
<g transform="matrix(1,0,0,1,-4.7583,-15.589)">
|
||||
<text x="181.54px" y="81.156px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:28px;fill:white;">Download JamKazam</text>
|
||||
<g transform="matrix(28,0,0,28,453.091,110.072)">
|
||||
</g>
|
||||
<text x="182.333px" y="110.072px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:28px;fill:white;">for Windows (Legacy)</text>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<image id="_Image1" width="200px" height="200px" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAyKADAAQAAAABAAAAyAAAAACbWz2VAAAFCElEQVR4Ae3bwU0bARiEUTaiDBqhkRQJhdAIfWzMBcvHDySLMC8nkGZZz/s1N+fhwT8CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwP8qcNzrg5/n+XR51/O93vfD3/N2HMd7+Yz8brSy383T4ZfHkP1u9GMcL9/9I7/k+b+XHq+xC78r2Ff8rk+Hn/6ErCiBOQEDmTu5wkXAQIqW7JyAgcydXOEiYCBFS3ZOwEDmTq5wETCQoiU7J2AgcydXuAgYSNGSnRMwkLmTK1wEDKRoyc4JGMjcyRUuAgZStGTnBAxk7uQKFwEDKVqycwIGMndyhYuAgRQt2TkBA5k7ucJFwECKluycgIHMnVzhImAgRUt2TsBA5k6ucBEwkKIlOydgIHMnV7gIGEjRkp0TMJC5kytcBAykaMnOCRjI3MkVLgIGUrRk5wQMZO7kChcBAylasnMCBjJ3coWLgIEULdk5AQOZO7nCRcBAipbsnICBzJ1c4SJgIEVLdk7AQOZOrnARMJCiJTsnYCBzJ1e4CBhI0ZKdEzCQuZMrXAQMpGjJzgkYyNzJFS4CBlK0ZOcEDGTu5AoXAQMpWrJzAgYyd3KFi4CBFC3ZOQEDmTu5wkXAQIqW7JyAgcydXOEiYCBFS3ZOwEDmTq5wETCQoiU7J2AgcydXuAgYSNGSnRMwkLmTK1wEDKRoyc4JGMjcyRUuAgZStGTnBAxk7uQKFwEDKVqycwIGMndyhYuAgRQt2TmB416Nz/N8urzr+V7v++HveTuO4718Rn43Wtnv5mm/ECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMBdBXxZ8a7cny/LX7bzZcVPu48fst/N0+GXx5D9bvTjm7wv3/0jv+T5v5cer7ELvyvYV/yuT4ef/H+QgCW6J2AgezfXOAgYSMAS3RMwkL2baxwEDCRgie4JGMjezTUOAgYSsET3BAxk7+YaBwEDCViiewIGsndzjYOAgQQs0T0BA9m7ucZBwEACluiegIHs3VzjIGAgAUt0T8BA9m6ucRAwkIAluidgIHs31zgIGEjAEt0TMJC9m2scBAwkYInuCRjI3s01DgIGErBE9wQMZO/mGgcBAwlYonsCBrJ3c42DgIEELNE9AQPZu7nGQcBAApbonoCB7N1c4yBgIAFLdE/AQPZurnEQMJCAJbonYCB7N9c4CBhIwBLdEzCQvZtrHAQMJGCJ7gkYyN7NNQ4CBhKwRPcEDGTv5hoHAQMJWKJ7Agayd3ONg4CBBCzRPQED2bu5xkHAQAKW6J6AgezdXOMgYCABS3RPwED2bq5xEDCQgCW6J2AgezfXOAgYSMAS3RMwkL2baxwEDCRgie4JGMjezTUOAgYSsET3BAxk7+YaBwEDCViiewIGsndzjYOAgQQs0T0BA9m7ucZBwEACluiegIHs3VzjIGAgAUt0T8BA9m6ucRAwkIAluidw3KvyeZ5Pl3c93+t9P/w9b8dxvJfPyO9GK/vdPO0XAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMCEwD8AEzCh1V2GrQAAAABJRU5ErkJggg=="/>
|
||||
<image id="_Image3" width="37px" height="37px" xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAlACUDAREAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABQQGBwH/xAAcEAACAwEBAQEAAAAAAAAAAAAAAwQhMQECIhH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCus9c88NgfKdtgRUl22SFSnbYEY5/1pFoEp22LAqU7bIipT9siKlO2wIxz/vQTQJTts0yKlO2yIqU/bBCpT9sCMa3vfVEWgSnbZpgVKdtgRUp+2BFSG973850ijkl3lM9WLIqUz1YETKZ6siidsk4Sf//Z"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 9.5 KiB |
|
|
@ -1,43 +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 499 146" 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-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
|
||||
<g>
|
||||
<g transform="matrix(1,0,0,1,-57.9807,-32.8429)">
|
||||
<path d="M556.58,69.309L556.58,142.277C556.58,162.413 540.232,178.761 520.096,178.761L94.466,178.761C74.33,178.761 57.982,162.413 57.982,142.277L57.982,69.309C57.982,49.173 74.33,32.825 94.466,32.825L520.096,32.825C540.232,32.825 556.58,49.173 556.58,69.309Z" style="fill:rgb(64,124,222);stroke:rgb(64,124,222);stroke-width:1px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.735399,0,0,0.685712,16.2125,4.37876)">
|
||||
<use xlink:href="#_Image1" x="0" y="0" width="200px" height="200px"/>
|
||||
</g>
|
||||
<g transform="matrix(0.835193,0,0,0.769777,7.35556,11.1156)">
|
||||
<g transform="matrix(0,45.5199,41.8804,0,154.724,117.573)">
|
||||
<clipPath id="_clip2">
|
||||
<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" clip-rule="nonzero"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#_clip2)">
|
||||
<g transform="matrix(-0,0.0285892,0.0285387,-0,-2.90011,-3.90471)">
|
||||
<use xlink:href="#_Image3" x="118.559" y="102.621" width="37px" height="37px"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(0.0344151,0,0,0.0374059,147.879,151.575)">
|
||||
<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(0.0344151,0,0,0.0374059,166.511,149.078)">
|
||||
<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(0.0344151,0,0,0.0374059,143.804,133.272)">
|
||||
<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>
|
||||
<g transform="matrix(1,0,0,1,-4.7583,-15.589)">
|
||||
<text x="181.54px" y="81.156px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:28px;fill:white;">Download JamKazam</text>
|
||||
<g transform="matrix(28,0,0,28,394.732,110.072)">
|
||||
</g>
|
||||
<text x="240.691px" y="110.072px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:28px;fill:white;">for Windows</text>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<image id="_Image1" width="200px" height="200px" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAyKADAAQAAAABAAAAyAAAAACbWz2VAAAFCElEQVR4Ae3bwU0bARiEUTaiDBqhkRQJhdAIfWzMBcvHDySLMC8nkGZZz/s1N+fhwT8CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwP8qcNzrg5/n+XR51/O93vfD3/N2HMd7+Yz8brSy383T4ZfHkP1u9GMcL9/9I7/k+b+XHq+xC78r2Ff8rk+Hn/6ErCiBOQEDmTu5wkXAQIqW7JyAgcydXOEiYCBFS3ZOwEDmTq5wETCQoiU7J2AgcydXuAgYSNGSnRMwkLmTK1wEDKRoyc4JGMjcyRUuAgZStGTnBAxk7uQKFwEDKVqycwIGMndyhYuAgRQt2TkBA5k7ucJFwECKluycgIHMnVzhImAgRUt2TsBA5k6ucBEwkKIlOydgIHMnV7gIGEjRkp0TMJC5kytcBAykaMnOCRjI3MkVLgIGUrRk5wQMZO7kChcBAylasnMCBjJ3coWLgIEULdk5AQOZO7nCRcBAipbsnICBzJ1c4SJgIEVLdk7AQOZOrnARMJCiJTsnYCBzJ1e4CBhI0ZKdEzCQuZMrXAQMpGjJzgkYyNzJFS4CBlK0ZOcEDGTu5AoXAQMpWrJzAgYyd3KFi4CBFC3ZOQEDmTu5wkXAQIqW7JyAgcydXOEiYCBFS3ZOwEDmTq5wETCQoiU7J2AgcydXuAgYSNGSnRMwkLmTK1wEDKRoyc4JGMjcyRUuAgZStGTnBAxk7uQKFwEDKVqycwIGMndyhYuAgRQt2TmB416Nz/N8urzr+V7v++HveTuO4718Rn43Wtnv5mm/ECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMBdBXxZ8a7cny/LX7bzZcVPu48fst/N0+GXx5D9bvTjm7wv3/0jv+T5v5cer7ELvyvYV/yuT4ef/H+QgCW6J2AgezfXOAgYSMAS3RMwkL2baxwEDCRgie4JGMjezTUOAgYSsET3BAxk7+YaBwEDCViiewIGsndzjYOAgQQs0T0BA9m7ucZBwEACluiegIHs3VzjIGAgAUt0T8BA9m6ucRAwkIAluidgIHs31zgIGEjAEt0TMJC9m2scBAwkYInuCRjI3s01DgIGErBE9wQMZO/mGgcBAwlYonsCBrJ3c42DgIEELNE9AQPZu7nGQcBAApbonoCB7N1c4yBgIAFLdE/AQPZurnEQMJCAJbonYCB7N9c4CBhIwBLdEzCQvZtrHAQMJGCJ7gkYyN7NNQ4CBhKwRPcEDGTv5hoHAQMJWKJ7Agayd3ONg4CBBCzRPQED2bu5xkHAQAKW6J6AgezdXOMgYCABS3RPwED2bq5xEDCQgCW6J2AgezfXOAgYSMAS3RMwkL2baxwEDCRgie4JGMjezTUOAgYSsET3BAxk7+YaBwEDCViiewIGsndzjYOAgQQs0T0BA9m7ucZBwEACluiegIHs3VzjIGAgAUt0T8BA9m6ucRAwkIAluidw3KvyeZ5Pl3c93+t9P/w9b8dxvJfPyO9GK/vdPO0XAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMCEwD8AEzCh1V2GrQAAAABJRU5ErkJggg=="/>
|
||||
<image id="_Image3" width="37px" height="37px" xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAlACUDAREAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABQQGBwH/xAAcEAACAwEBAQEAAAAAAAAAAAAAAwQhMQECIhH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCus9c88NgfKdtgRUl22SFSnbYEY5/1pFoEp22LAqU7bIipT9siKlO2wIxz/vQTQJTts0yKlO2yIqU/bBCpT9sCMa3vfVEWgSnbZpgVKdtgRUp+2BFSG973850ijkl3lM9WLIqUz1YETKZ6siidsk4Sf//Z"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 9.5 KiB |
|
|
@ -1,12 +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 256 256" 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>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M124.9,25.9L123.1,27.5L122.5,156.7L104.4,139.1C87.8,122.8 86.2,121.5 84.1,121.5C82.4,121.5 81.4,122 80.4,123.2C77.5,126.9 77.3,126.7 101.8,151.2C114.3,163.7 125.3,174.2 126.2,174.5C127.2,174.9 128.4,174.9 129.4,174.5C130.2,174.2 141.3,163.8 153.8,151.4C175.3,130.2 176.7,128.7 176.7,126.6C176.7,123.6 174.5,121.4 171.5,121.4C169.5,121.4 167.7,123 151.4,139.1L133.4,156.9L133.3,92.7C133.2,46.7 132.9,28.1 132.4,27.1C131.7,25.7 129.3,24.2 127.6,24.2C127.2,24.3 125.9,25.1 124.9,25.9Z" style="fill:rgb(64,124,222);fill-rule:nonzero;"/>
|
||||
<path d="M11.6,147.2L10,148.8L10,227.9L13.8,231.7L127.7,231.7C213,231.7 241.9,231.5 243,230.9C246.1,229.3 246,230.3 246.1,188.6C246.1,149.6 246.1,149 244.7,147.3C242.9,145 239.5,145 237.3,147.2L235.7,148.8L235.7,221.2L20.4,221.2L20.4,185.1C20.4,149.6 20.4,149 19,147.3C17.2,145 13.8,145 11.6,147.2Z" style="fill:rgb(64,124,222);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
|
@ -1,13 +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 256 256" 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>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M114.7,10.6C80.5,14.5 49.1,34 29.4,63.5C25.2,69.9 18.4,83.8 15.9,91.1C8,115.2 8,140.8 16.1,165.1C33.5,217 85.2,250.8 139.3,245.4C183.9,241 223.1,210.6 238.9,168.2C246.2,148.4 248,125.3 243.7,104.4C233.7,55.6 192.3,17.2 142.7,10.9C135.6,9.9 121.7,9.8 114.7,10.6ZM140.5,19C196.1,25 237.5,71.6 237.5,128.1C237.5,165.1 219.6,198.8 189,219.3C167.9,233.4 141.1,239.8 115,236.8C77.7,232.5 46,210.1 29.6,176.5C14.7,146.2 14.8,109.6 29.7,79.3C35.3,67.7 41,59.8 50.4,50.3C67.4,33 90.5,21.8 114.9,19C120.9,18.3 134.3,18.3 140.5,19Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
|
||||
<path d="M104.3,86.7C104.1,87.1 104.1,104.9 104.1,126.3L104.3,165.2L118.9,165.2L118.9,86.3L111.7,86.1C106.3,86 104.5,86.2 104.3,86.7Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
|
||||
<path d="M136.6,87.3C136.4,88.4 136.4,149.5 136.7,162L136.8,165.5L144.3,165.3L151.7,165.1L151.7,86.3L144.3,86.1C136.9,86 136.8,86 136.6,87.3Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
|
@ -1,12 +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 256 256" 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>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M115,10.4C93.4,12.8 72.1,21.7 54.5,35.4C49.4,39.5 40,48.8 35.7,54.2C22.7,70.3 14.1,90.4 10.9,111.5C9.7,120.1 9.7,136 10.9,144.5C15.3,174 29.7,199.7 52.8,219C78.4,240.4 113.5,250.1 146.3,244.8C197.7,236.4 237.4,196.2 245.1,144.7C246.3,136.3 246.3,119.9 245.1,111.4C241.4,86.2 230.7,64.4 213,46.1C202.5,35.2 192.4,27.9 179.3,21.6C159.4,12 136.4,8 115,10.4ZM146,20.7C193.8,29.3 229.1,65.9 235.9,114.2C236.8,120.8 236.7,136.8 235.6,143.7C230.8,174.4 214.5,200.4 189.1,217.8C168.3,232 142.2,238.7 117.3,236.2C78.4,232.3 44.2,207.5 28.6,172C21.3,155.4 18.5,139.2 19.6,120.5C21.5,86.8 40.8,54.3 69.6,36.2C82.5,28.1 98,22.3 111.8,20.4C114.4,20 117.3,19.6 118.3,19.5C122.1,19.1 140.9,19.8 146,20.7Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
|
||||
<path d="M110,81.1C106.9,82.4 107,80.4 107,128.1L107,172.5L108.3,173.9C109.1,174.7 110.4,175.2 111.6,175.2C113.4,175.2 116.8,172.5 139.5,153.8C153.7,142 165.9,131.8 166.5,131.2C167,130.6 167.5,129.1 167.5,128.1C167.5,127 167,125.6 166.5,125C165.9,124.4 155.1,115.3 142.4,104.8C129.8,94.4 118.2,84.8 116.7,83.6C113.8,81 111.8,80.3 110,81.1ZM136.7,112.3C146.9,120.7 155.3,127.8 155.3,127.9C155.4,128.1 148,134.4 138.9,141.9C129.8,149.5 121.1,156.6 119.6,157.9L116.8,160.3L116.8,128C116.8,102.2 117,95.9 117.6,96.3C117.9,96.7 126.6,103.9 136.7,112.3Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 976 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |