Files
gameno-dashboard/src/utils/professorShare.js
T

75 lines
2.9 KiB
JavaScript

// /src/utils/professorShare.js
// Mirrors gameno-api/utils/professorShare.js so the dashboard can preview payout
// calculations client-side before saving a class.
const toNonNegativeNumber = (value) => {
const n = Number(value);
if (!Number.isFinite(n) || n < 0) return 0;
return n;
};
const toPercentage = (value) => Math.min(100, toNonNegativeNumber(value));
const parseClockTime = (value) => {
const raw = String(value || '').trim();
const match = raw.match(/^(\d{1,2}):(\d{2})$/);
if (!match) return null;
const hours = Number(match[1]);
const minutes = Number(match[2]);
if (hours > 23 || minutes > 59) return null;
return hours * 60 + minutes;
};
export function calculateSessionDurationHours(startTime, endTime) {
const start = parseClockTime(startTime);
const end = parseClockTime(endTime);
if (start == null || end == null) return 0;
let diffMinutes = end - start;
if (diffMinutes <= 0) diffMinutes += 24 * 60;
return diffMinutes / 60;
}
export function resolveSessionDurationHours({ hoursPerSection, startTime, endTime } = {}) {
const hours = toNonNegativeNumber(hoursPerSection);
if (hours > 0) return hours;
return calculateSessionDurationHours(startTime, endTime);
}
export function calculatePercentageShare({ payoutPercentage = 0, revenue = 0, serviceFeePerPerson = 0, studentsCount = 0 } = {}) {
const totalServiceFee = toNonNegativeNumber(serviceFeePerPerson) * toNonNegativeNumber(studentsCount);
const netRevenue = Math.max(0, toNonNegativeNumber(revenue) - totalServiceFee);
return (toPercentage(payoutPercentage) / 100) * netRevenue;
}
export function calculateHourlyShare({ payoutHourlyRate = 0, sessionDurationHours = 0, sessionsCount = 0 } = {}) {
return toNonNegativeNumber(payoutHourlyRate) * toNonNegativeNumber(sessionDurationHours) * toNonNegativeNumber(sessionsCount);
}
export function calculateExtraExpenses({ extraExpensePerSession = 0, sessionsCount = 0 } = {}) {
return toNonNegativeNumber(extraExpensePerSession) * toNonNegativeNumber(sessionsCount);
}
export function calculateProfessorPayout(params = {}) {
const baseShare = params.payoutType === 'hourly'
? calculateHourlyShare(params)
: calculatePercentageShare(params);
const extraExpenses = calculateExtraExpenses(params);
return {
baseShare,
extraExpenses,
totalPayout: baseShare + extraExpenses
};
}
export function calculateNetProfit({ totalIncome = 0, professorTotalPayout = 0 } = {}) {
return toNonNegativeNumber(totalIncome) - toNonNegativeNumber(professorTotalPayout);
}
export function calculatePendingReceivables(expectedRevenue = 0, actualReceivedRevenue = 0) {
return Math.max(0, toNonNegativeNumber(expectedRevenue) - toNonNegativeNumber(actualReceivedRevenue));
}
export function calculateOverpaidAmount(expectedRevenue = 0, actualReceivedRevenue = 0) {
return Math.max(0, toNonNegativeNumber(actualReceivedRevenue) - toNonNegativeNumber(expectedRevenue));
}