diff --git a/jam-ui/src/components/affiliate/JKAffiliateEarnings.js b/jam-ui/src/components/affiliate/JKAffiliateEarnings.js new file mode 100644 index 000000000..5e80fde83 --- /dev/null +++ b/jam-ui/src/components/affiliate/JKAffiliateEarnings.js @@ -0,0 +1,66 @@ +import React, { useState, useEffect } from 'react'; + +import { Card, CardBody, Table } from 'reactstrap'; +import FalconCardHeader from '../common/FalconCardHeader'; +import { useTranslation } from 'react-i18next'; +import { getAffiliatePayments } from '../../helpers/rest'; +import { monthName } from '../../helpers/utils'; +import { getDisplayName } from '../../helpers/subscriptionHelper'; + +const JKAffiliateEarnings = () => { + const { t } = useTranslation('affiliate'); + const [payments, setPayments] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + setLoading(true); + getAffiliatePayments().then(resp => { + return resp.json(); + }).then(data => { + console.log('payments', data); + setPayments(data.payments); + }).finally(() => { + setLoading(false); + }); + }, []); + + return ( + + + + {payments && payments.length === 0 && !loading ? ( +

{t('earnings.no_data')}

+ ) : payments && payments.length > 0 && ( + + + + + + + + + + + {payments.map((payment, index) => ( + + + + + + + ))} + +
{t('earnings.list.header.date')}{t('earnings.list.header.subscriptions')}{t('earnings.list.header.jamtracks')}{t('earnings.list.header.earnings')}
{monthName(payment.month-1)} - {payment.year} + {payment.subscriptions.map((subscription, index) => ( +
+ {getDisplayName(subscription.plan)} - {subscription.count} +
+ ))} +
{payment.jamtracks_sold}${(payment.due_amount_in_cents/100).toFixed(2)}
+ )} +
+
+ ); +}; + +export default JKAffiliateEarnings; diff --git a/jam-ui/src/components/dashboard/JKDashboardMain.js b/jam-ui/src/components/dashboard/JKDashboardMain.js index 6488f75a4..4b34c1e0b 100644 --- a/jam-ui/src/components/dashboard/JKDashboardMain.js +++ b/jam-ui/src/components/dashboard/JKDashboardMain.js @@ -45,6 +45,7 @@ import JKAffiliateProgram from '../affiliate/JKAffiliateProgram'; import JKAffiliatePayee from '../affiliate/JKAffiliatePayee'; import JKAffiliateLinks from '../affiliate/JKAffiliateLinks'; import JKAffiliateSignups from '../affiliate/JKAffiliateSignups'; +import JKAffiliateEarnings from '../affiliate/JKAffiliateEarnings'; //import loadable from '@loadable/component'; @@ -278,6 +279,7 @@ function JKDashboardMain() { + {/*Redirect*/} diff --git a/jam-ui/src/components/page/JKAccountSubscription.js b/jam-ui/src/components/page/JKAccountSubscription.js index 237fe81f1..bb3c79de8 100644 --- a/jam-ui/src/components/page/JKAccountSubscription.js +++ b/jam-ui/src/components/page/JKAccountSubscription.js @@ -8,6 +8,8 @@ import JKSubscriptionPlaytime from '../profile/JKSubscriptionPlaytime'; import { getSubscription } from '../../helpers/rest'; +import { getDisplayName } from '../../helpers/subscriptionHelper'; + const JKAccountSubscription = () => { const { t } = useTranslation('account'); const [userPlan, setUserPlan] = useState(null); @@ -23,16 +25,16 @@ const JKAccountSubscription = () => { }); }, []); - const getDisplayName = planCode => { - if (planCode == '') { - planCode = null; - } - const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); - if (plan) { - return plan.name; - } - return `Unknown plan code=${planCode}`; - }; + // const getDisplayName = planCode => { + // if (planCode == '') { + // planCode = null; + // } + // const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); + // if (plan) { + // return plan.name; + // } + // return `Unknown plan code=${planCode}`; + // }; return ( diff --git a/jam-ui/src/components/profile/JKSubscriptionPlan.js b/jam-ui/src/components/profile/JKSubscriptionPlan.js index 9a4031b88..858e180b6 100644 --- a/jam-ui/src/components/profile/JKSubscriptionPlan.js +++ b/jam-ui/src/components/profile/JKSubscriptionPlan.js @@ -10,6 +10,8 @@ import JKModalDialog from '../common/JKModalDialog'; import { getSubscription, changeSubscription } from '../../helpers/rest'; +import { getDisplayNamePrice, getDisplayCycle } from '../../helpers/subscriptionHelper'; + function JKSubscriptionPlan({ userPlan, setUserPlan, getDisplayName }) { const { t } = useTranslation('account'); @@ -62,32 +64,32 @@ function JKSubscriptionPlan({ userPlan, setUserPlan, getDisplayName }) { setValue('plan_code', selectedOption.value); }; - const getDisplayNamePrice = planCode => { - if (planCode == '') { - planCode = null; - } - const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); - if (plan) { - return plan.price; - } - return `Unknown plan code=${planCode}`; - }; + // const getDisplayNamePrice = planCode => { + // if (planCode == '') { + // planCode = null; + // } + // const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); + // if (plan) { + // return plan.price; + // } + // return `Unknown plan code=${planCode}`; + // }; - const getDisplayCycle = planCode => { - if (planCode == '') { - planCode = null; - } - for (const subscriptionCode of window.gon.global.subscription_codes) { - if (planCode === subscriptionCode.id) { - if (subscriptionCode.cycle === 'year') { - return 'annual'; - } else { - return subscriptionCode.cycle + 'ly'; - } - } - } - return `Unknown plan code=${planCode}`; - }; + // const getDisplayCycle = planCode => { + // if (planCode == '') { + // planCode = null; + // } + // for (const subscriptionCode of window.gon.global.subscription_codes) { + // if (planCode === subscriptionCode.id) { + // if (subscriptionCode.cycle === 'year') { + // return 'annual'; + // } else { + // return subscriptionCode.cycle + 'ly'; + // } + // } + // } + // return `Unknown plan code=${planCode}`; + // }; const onSubmit = () => { const planCode = getValues('plan_code'); diff --git a/jam-ui/src/components/profile/JKSubscriptionPlaytime.js b/jam-ui/src/components/profile/JKSubscriptionPlaytime.js index e9c791b0d..04e312398 100644 --- a/jam-ui/src/components/profile/JKSubscriptionPlaytime.js +++ b/jam-ui/src/components/profile/JKSubscriptionPlaytime.js @@ -2,6 +2,7 @@ import React, { useEffect, useState, useRef } from 'react'; import { Card, CardHeader, CardBody, Label } from 'reactstrap'; import { useTranslation } from 'react-i18next'; import { formatDateShort } from '../../helpers/utils'; +import { planNameWithCycle, displayTime } from '../../helpers/subscriptionHelper'; function JKSubscriptionPlaytime({ userPlan, getDisplayName }) { const { t } = useTranslation('account'); @@ -11,67 +12,67 @@ function JKSubscriptionPlaytime({ userPlan, getDisplayName }) { const [billingAddendum, setBillingAddendum] = useState(''); // [TODO: addendum to the warning message about billing, if needed] const showPaymentInfoRef = useRef(false); - const displayTime = until_time => { - if (until_time < 0) return 'no time'; + // const displayTime = until_time => { + // if (until_time < 0) return 'no time'; - const untilTime = getTimeRemaining(until_time * 1000); + // const untilTime = getTimeRemaining(until_time * 1000); - let timeString = ''; - if (untilTime.days !== 0) timeString += `${untilTime.days} days, `; - if (untilTime.hours !== 0 || timeString.length > 0) timeString += `${untilTime.hours} hours, `; - if (untilTime.minutes !== 0 || timeString.length > 0) timeString += `${untilTime.minutes} minutes `; - if (timeString === '') timeString = 'now!'; + // let timeString = ''; + // if (untilTime.days !== 0) timeString += `${untilTime.days} days, `; + // if (untilTime.hours !== 0 || timeString.length > 0) timeString += `${untilTime.hours} hours, `; + // if (untilTime.minutes !== 0 || timeString.length > 0) timeString += `${untilTime.minutes} minutes `; + // if (timeString === '') timeString = 'now!'; - return timeString; - }; + // return timeString; + // }; - const getTimeRemaining = t => { - if (t < 0) t = -t; + // const getTimeRemaining = t => { + // if (t < 0) t = -t; - const seconds = Math.floor((t / 1000) % 60); - const minutes = Math.floor((t / 1000 / 60) % 60); - const hours = Math.floor((t / (1000 * 60 * 60)) % 24); - const days = Math.floor(t / (1000 * 60 * 60 * 24)); + // const seconds = Math.floor((t / 1000) % 60); + // const minutes = Math.floor((t / 1000 / 60) % 60); + // const hours = Math.floor((t / (1000 * 60 * 60)) % 24); + // const days = Math.floor(t / (1000 * 60 * 60 * 24)); - return { - total: t, - days: days, - hours: hours, - minutes: minutes, - seconds: seconds - }; - }; + // return { + // total: t, + // days: days, + // hours: hours, + // minutes: minutes, + // seconds: seconds + // }; + // }; - const getDisplayNamePrice = planCode => { - if (planCode == '') { - planCode = null; - } - const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); - if (plan) { - return plan.price; - } - return `Unknown plan code=${planCode}`; - }; + // const getDisplayNamePrice = planCode => { + // if (planCode == '') { + // planCode = null; + // } + // const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); + // if (plan) { + // return plan.price; + // } + // return `Unknown plan code=${planCode}`; + // }; - const getDisplayCycle = planCode => { - if (planCode == '') { - planCode = null; - } - for (const subscriptionCode of window.gon.global.subscription_codes) { - if (planCode === subscriptionCode.id) { - if (subscriptionCode.cycle === 'year') { - return 'annual'; - } else { - return subscriptionCode.cycle + 'ly'; - } - } - } - return `Unknown plan code=${planCode}`; - }; + // const getDisplayCycle = planCode => { + // if (planCode == '') { + // planCode = null; + // } + // for (const subscriptionCode of window.gon.global.subscription_codes) { + // if (planCode === subscriptionCode.id) { + // if (subscriptionCode.cycle === 'year') { + // return 'annual'; + // } else { + // return subscriptionCode.cycle + 'ly'; + // } + // } + // } + // return `Unknown plan code=${planCode}`; + // }; - const planNameWithCycle = planCode => { - return getDisplayName(planCode) + ' (' + getDisplayCycle(planCode) + ')'; - }; + // const planNameWithCycle = planCode => { + // return getDisplayName(planCode) + ' (' + getDisplayCycle(planCode) + ')'; + // }; useEffect(() => { if (userPlan) { diff --git a/jam-ui/src/helpers/rest.js b/jam-ui/src/helpers/rest.js index e1ea55675..bb44ebb8c 100644 --- a/jam-ui/src/helpers/rest.js +++ b/jam-ui/src/helpers/rest.js @@ -352,6 +352,14 @@ export const getAffiliateSignups = (options = {}) => { }); } +export const getAffiliatePayments = () => { + return new Promise((resolve, reject) => { + apiFetch(`/affiliate_partners/payments`) + .then(response => resolve(response)) + .catch(error => reject(error)) + }); +} + export const postAffiliatePartnerData = (userId, params) => { return new Promise((resolve, reject) => { apiFetch(`/users/${userId}/affiliate_partner`, { diff --git a/jam-ui/src/helpers/subscriptionHelper.js b/jam-ui/src/helpers/subscriptionHelper.js new file mode 100644 index 000000000..01c42821a --- /dev/null +++ b/jam-ui/src/helpers/subscriptionHelper.js @@ -0,0 +1,75 @@ +export const getDisplayName = planCode => { + if (planCode == '') { + planCode = null; + } + const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); + if (plan) { + return plan.name; + } + return `Unknown plan code=${planCode}`; +}; + +export const getDisplayNamePrice = planCode => { + if (planCode == '') { + planCode = null; + } + const plan = window.gon.global.subscription_codes.find(plan => plan.id === planCode); + if (plan) { + return plan.price; + } + return `Unknown plan code=${planCode}`; +}; + +export const getDisplayCycle = planCode => { + if (planCode == '') { + planCode = null; + } + for (const subscriptionCode of window.gon.global.subscription_codes) { + if (planCode === subscriptionCode.id) { + if (subscriptionCode.cycle === 'year') { + return 'annual'; + } else { + return subscriptionCode.cycle + 'ly'; + } + } + } + return `Unknown plan code=${planCode}`; +}; + +export const planNameWithCycle = planCode => { + return getDisplayName(planCode) + ' (' + getDisplayCycle(planCode) + ')'; +}; + +export const displayTime = until_time => { + if (until_time < 0) return 'no time'; + + const untilTime = getTimeRemaining(until_time * 1000); + + let timeString = ''; + if (untilTime.days !== 0) timeString += `${untilTime.days} days, `; + if (untilTime.hours !== 0 || timeString.length > 0) timeString += `${untilTime.hours} hours, `; + if (untilTime.minutes !== 0 || timeString.length > 0) timeString += `${untilTime.minutes} minutes `; + if (timeString === '') timeString = 'now!'; + + return timeString; +}; + +const getTimeRemaining = t => { + if (t < 0) t = -t; + + const seconds = Math.floor((t / 1000) % 60); + const minutes = Math.floor((t / 1000 / 60) % 60); + const hours = Math.floor((t / (1000 * 60 * 60)) % 24); + const days = Math.floor(t / (1000 * 60 * 60 * 24)); + + return { + total: t, + days: days, + hours: hours, + minutes: minutes, + seconds: seconds + }; +}; + + + diff --git a/jam-ui/src/helpers/utils.js b/jam-ui/src/helpers/utils.js index 222fd1774..52794c9ae 100644 --- a/jam-ui/src/helpers/utils.js +++ b/jam-ui/src/helpers/utils.js @@ -243,6 +243,10 @@ const months = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); +export const monthName = (monthNumber) => { + return months[monthNumber]; +} + export const formatDateShort = (dateString) => { const date = dateString instanceof Date ? dateString : new Date(dateString); return months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear(); diff --git a/jam-ui/src/i18n/locales/en/affiliate.json b/jam-ui/src/i18n/locales/en/affiliate.json index 77bed5e12..b71c33614 100644 --- a/jam-ui/src/i18n/locales/en/affiliate.json +++ b/jam-ui/src/i18n/locales/en/affiliate.json @@ -77,5 +77,18 @@ "signups": "Signups" } } + }, + "earnings": { + "page_title": "Earnings", + "no_data": "No earnings yet", + "load_more": "Load More", + "list": { + "header": { + "date": "Date", + "subscriptions": "Subscriptions", + "jamtracks": "JamTracks", + "earnings": "Earnings" + } + } } } \ No newline at end of file