1const steps = [ 2 { range: [0, 1], label: 'Hobby site / Average Traffic' }, 3 { range: [1, 2], label: 'Small E-commerce' }, 4 { range: [2, 6], label: 'Medium E-commerce' }, 5 { range: [6], label: 'Large E-commerce' } 6]; 7 8const cleanNumber = (val) => Math.ceil(Math.abs(val)); 9 10/** 11 * Shared pricing-calculator store. Plain object with the computed values 12 * exposed as getters; the `dnsimple-pricing-calculator` element mutates it and 13 * re-renders. 14 */ 15const calc = { 16 seats: 1, 17 zones: 1, 18 queries: 0, 19 infoPanelOpen: false, 20 plans: [], 21 22 get roundedZones() { 23 return cleanNumber(calc.zones); 24 }, 25 26 get purchasedSeats() { 27 return calc.seats - 1; 28 }, 29 30 get queryBlocks() { 31 const blocks = Math.abs(calc.queries / 1000000); 32 return blocks > 1 ? blocks : 1; 33 }, 34 35 get trafficDescriptor() { 36 return steps.find((step) => { 37 const [min, max] = step.range; 38 if (!max) return true; 39 return calc.queryBlocks >= min && calc.queryBlocks <= max; 40 }).label; 41 }, 42 43 /** 44 * Normalizes plan pricing to numbers and appends the custom Enterprise plan. 45 * 46 * @param {Array<Object>} plans 47 * @returns {void} 48 */ 49 commitPlans(plans) { 50 calc.plans = plans.map((plan) => ({ 51 ...plan, 52 price: Number(plan.price), 53 price_per_query_block: Number(plan.price_per_query_block), 54 included_queries_per_zone: plan.included_queries_per_zone == null ? null : Number(plan.included_queries_per_zone), 55 overage_price_per_million: plan.overage_price_per_million == null ? null : Number(plan.overage_price_per_million), 56 price_per_seat: Number(plan.price_per_seat), 57 price_per_zone: Number(plan.price_per_zone) 58 })).concat({ name: 'Custom', display_name: 'Enterprise', custom: true, price: 0 }); 59 }, 60 61 /** 62 * What one zone costs in query fees under a plan. 63 * 64 * A plan with an allowance charges only the volume above it, rounded up to 65 * started millions, which is how the invoice rounds. A plan without one 66 * charges from the zone's first query, which is what it did before 67 * allowances existed and is still a real state for any plan with no 68 * configuration. 69 * 70 * @param {Object} plan 71 * @returns {number} 72 */ 73 queryFeePerZone(plan) { 74 return calc.billedMillions(plan) * calc.queryRate(plan); 75 }, 76 77 /** 78 * The millions a zone is billed for under a plan: the volume above its 79 * allowance rounded up to started millions, or the whole volume when the plan 80 * has no allowance. 81 * 82 * Split out from the fee so the itemized breakdown shows the same multiplier 83 * the fee was computed from. Printing a different one is how the working-out 84 * column came to contradict the amount beside it. 85 * 86 * @param {Object} plan 87 * @returns {number} 88 */ 89 billedMillions(plan) { 90 if (plan.included_queries_per_zone == null) return calc.queryBlocks; 91 92 return Math.ceil(Math.max(0, calc.queries - plan.included_queries_per_zone) / 1000000); 93 }, 94 95 /** 96 * The per-million price a zone's billable volume is charged at: the overage 97 * rate for a plan with an allowance, the block rate for one without. 98 * 99 * @param {Object} plan 100 * @returns {number} 101 */ 102 queryRate(plan) { 103 return plan.included_queries_per_zone == null ? plan.price_per_query_block : plan.overage_price_per_million; 104 }, 105 106 /** 107 * @param {number} planId 108 * @returns {?Object} 109 */ 110 findPlanById(planId) { 111 return calc.plans.find(({ id }) => id === planId); 112 }, 113 114 /** 115 * @param {number} planId 116 * @returns {{zones:number, seats:number, queries:number, subscription:number, sum:number}} 117 */ 118 totalsForPlan(planId) { 119 const plan = calc.findPlanById(planId); 120 const zones = calc.roundedZones * plan.price_per_zone; 121 const seats = plan.price_per_seat ? calc.purchasedSeats * plan.price_per_seat : 0; 122 const queries = calc.queryFeePerZone(plan) * calc.roundedZones; 123 124 return { 125 zones, 126 seats, 127 queries, 128 subscription: plan.price, 129 sum: seats + queries + zones + plan.price 130 }; 131 } 132}; 133 134export default calc;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.