Skip to main content

max / makenotwork

Switch price inputs from cents to dollars All creator-facing price inputs now accept dollar values with auto-conversion to cents via hidden fields: - PWYW minimum price (item pricing tab) - Subscription tier monthly price (project subscriptions tab) - Promo code fixed discount (project promotions tab) - Inline item price edit (item edit row) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-03 02:50 UTC
Commit: c8945a82e9d55ffa78ad4aa0ae2421f07ba67597
Parent: 523c90b
5 files changed, +60 insertions, -14 deletions
@@ -38,7 +38,7 @@ Usability audit grade: B. Complexity C+, Completeness B+, Learnability B, Discov
38 38 ### High (significant friction reduction)
39 39
40 40 - [ ] **[MEDIUM]** Restructure user dashboard tabs — show 4 core tabs (Account, Projects, Payments, Support) by default. Collapse SyncKit, SSH Keys, Forums, Media into "More Tools" overflow section. Current 11 tabs overwhelm new creators
41 - - [ ] **[MEDIUM]** Fix price input to use dollars, not cents — promo code and subscription tier forms accept cents (e.g. "500" for $5). Add live preview ("= $5.00") or switch to dollar input with auto-conversion
41 + - [x] **[MEDIUM]** Fix price input to use dollars, not cents — PWYW min, subscription tier, promo code fixed discount, and inline item edit all now accept dollars with auto-conversion to cents
42 42 - [x] **[MEDIUM]** Standardize pricing terminology — item wizard now says "One-Time Purchase" to match project wizard, paywall, landing page, and docs
43 43 - [x] **[MEDIUM]** Add self-service refund UI for creators — new "Sales" tab on item dashboard with per-transaction refund buttons, Stripe refund API integration
44 44
@@ -13,7 +13,9 @@
13 13 </select>
14 14 </td>
15 15 <td>
16 - <input type="number" name="price_cents" value="" placeholder="0" class="edit-input" style="width: 80px;">
16 + <input type="number" step="0.01" min="0" placeholder="0.00" class="edit-input" style="width: 80px;"
17 + oninput="this.nextElementSibling.value = Math.round(parseFloat(this.value || 0) * 100)">
18 + <input type="hidden" name="price_cents" value="0">
17 19 </td>
18 20 <td>{{ item.sales }}</td>
19 21 <td>{{ item.revenue }}</td>
@@ -21,13 +21,23 @@
21 21
22 22 <div id="pwyw-settings" style="{% if !item.pwyw_enabled %}display: none;{% endif %}">
23 23 <div class="form-group">
24 - <label for="pwyw-min">Minimum price (cents)</label>
25 - <input type="number" id="pwyw-min" name="pwyw_min_cents"
26 - value="{% if let Some(min) = item.pwyw_min_cents %}{{ min }}{% endif %}"
27 - min="0" placeholder="0 (any amount)">
28 - <p class="form-hint">The lowest amount a buyer can pay, in cents. 0 = any amount.</p>
24 + <label for="pwyw-min-dollars">Minimum price ($)</label>
25 + <input type="number" id="pwyw-min-dollars" step="0.01" min="0" placeholder="0.00">
26 + <input type="hidden" id="pwyw-min-cents" name="pwyw_min_cents"
27 + value="{% if let Some(min) = item.pwyw_min_cents %}{{ min }}{% endif %}">
28 + <p class="form-hint">The lowest amount a buyer can pay. $0 = any amount.</p>
29 29 </div>
30 30 </div>
31 + <script>
32 + (function() {
33 + var dollars = document.getElementById('pwyw-min-dollars');
34 + var cents = document.getElementById('pwyw-min-cents');
35 + if (cents.value) dollars.value = (parseInt(cents.value, 10) / 100).toFixed(2);
36 + dollars.addEventListener('input', function() {
37 + cents.value = Math.round(parseFloat(this.value || 0) * 100);
38 + });
39 + })();
40 + </script>
31 41
32 42 <button class="primary" type="submit">
33 43 Save PWYW Settings
@@ -38,9 +38,10 @@
38 38 </select>
39 39 </div>
40 40 <div class="form-group" style="margin-bottom: 0;">
41 - <label for="pc-value" style="font-size: 0.85rem;">Value</label>
42 - <input type="number" id="pc-value" name="discount_value" min="1"
41 + <label for="pc-value-input" style="font-size: 0.85rem;">Value</label>
42 + <input type="number" id="pc-value-input" min="1" step="1"
43 43 placeholder="e.g. 50" style="width: 100px;">
44 + <input type="hidden" id="pc-value-hidden" name="discount_value">
44 45 </div>
45 46 </div>
46 47 <div id="trial-fields" class="form-group" style="margin-bottom: 0; display: none;">
@@ -70,7 +71,31 @@
70 71 {% endif %}
71 72 <button class="secondary" type="submit" style="height: fit-content;">Create</button>
72 73 </div>
73 - <p class="form-hint" style="margin-top: 0.5rem;">For percentage: enter 1-100. For fixed: enter amount in cents (e.g. 500 = $5.00). Free access codes auto-generate if left blank.</p>
74 + <p class="form-hint" style="margin-top: 0.5rem;">For percentage: enter 1-100. For fixed: enter dollar amount (e.g. 5 = $5.00 off). Free access codes auto-generate if left blank.</p>
75 + <script>
76 + (function() {
77 + var typeSelect = document.getElementById('pc-type');
78 + var input = document.getElementById('pc-value-input');
79 + var hidden = document.getElementById('pc-value-hidden');
80 + function updatePromoInput() {
81 + if (typeSelect.value === 'fixed') {
82 + input.step = '0.01';
83 + input.placeholder = 'e.g. 5.00';
84 + } else {
85 + input.step = '1';
86 + input.placeholder = 'e.g. 50';
87 + }
88 + syncValue();
89 + }
90 + function syncValue() {
91 + var val = parseFloat(input.value || 0);
92 + hidden.value = typeSelect.value === 'fixed' ? Math.round(val * 100) : Math.round(val);
93 + }
94 + typeSelect.addEventListener('change', updatePromoInput);
95 + input.addEventListener('input', syncValue);
96 + updatePromoInput();
97 + })();
98 + </script>
74 99 </form>
75 100 </details>
76 101
@@ -28,11 +28,20 @@
28 28 <textarea id="tier-description" name="description" placeholder="What subscribers get..." maxlength="2000"></textarea>
29 29 </div>
30 30 <div class="form-group">
31 - <label for="tier-price">Monthly Price (USD)</label>
32 - <input type="number" id="tier-price" name="price_cents" min="100" step="1" placeholder="500" required
33 - title="Price in cents (e.g. 500 = $5.00)">
34 - <span style="font-size: 0.85rem; opacity: 0.6;">In cents. Minimum $1.00 (100 cents).</span>
31 + <label for="tier-price-dollars">Monthly Price ($)</label>
32 + <input type="number" id="tier-price-dollars" step="0.01" min="1.00" placeholder="5.00" required>
33 + <input type="hidden" id="tier-price-cents" name="price_cents">
34 + <span style="font-size: 0.85rem; opacity: 0.6;">Minimum $1.00.</span>
35 35 </div>
36 + <script>
37 + (function() {
38 + var dollars = document.getElementById('tier-price-dollars');
39 + var cents = document.getElementById('tier-price-cents');
40 + dollars.addEventListener('input', function() {
41 + cents.value = Math.round(parseFloat(this.value || 0) * 100);
42 + });
43 + })();
44 + </script>
36 45 <button class="primary" type="submit">Create Tier</button>
37 46 </form>
38 47 </details>