<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohamed Ghanem</title>
    <description>The latest articles on DEV Community by Mohamed Ghanem (@wizekin).</description>
    <link>https://dev.to/wizekin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4200274%2F719d7c44-4a68-4fb9-bee6-48742cd78bf5.png</url>
      <title>DEV Community: Mohamed Ghanem</title>
      <link>https://dev.to/wizekin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wizekin"/>
    <language>en</language>
    <item>
      <title>Three small browser tools, three different correctness problems</title>
      <dc:creator>Mohamed Ghanem</dc:creator>
      <pubDate>Thu, 22 Oct 2026 16:12:58 +0000</pubDate>
      <link>https://dev.to/wizekin/three-small-browser-tools-three-different-correctness-problems-4j33</link>
      <guid>https://dev.to/wizekin/three-small-browser-tools-three-different-correctness-problems-4j33</guid>
      <description>&lt;p&gt;A calculator can look polished and still be wrong. An inventory estimate can use the right formula against the wrong stock figure. A worksheet can print a neat answer key that belongs to a different set of questions.&lt;/p&gt;

&lt;p&gt;Wizekin's three new browser tools made these differences concrete. Here are the implementation decisions behind a handmade pricing calculator, an inventory reorder calculator, and an arithmetic worksheet generator.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. State what a percentage is a percentage of
&lt;/h2&gt;

&lt;p&gt;For handmade pricing, “add 30% profit” is ambiguous. A markup is measured against cost. A margin is measured against selling price.&lt;/p&gt;

&lt;p&gt;For a unit cost of 7.30:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;markupPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;7.30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// 9.49&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;marginPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;7.30&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// about 10.43&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selling fees introduce another dependency on the final price. If the channel takes 5% of the selling price plus 0.30 per item, and the target margin is 30%, solve for price:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sellingPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unitCost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fixedFee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;feeRate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;denominator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;margin&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;feeRate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;denominator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Margin plus percentage fee must be below 100%.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unitCost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fixedFee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;denominator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;sellingPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;7.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 11.692307...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function takes fractions, not whole percentage numbers. The UI accepts 30 and 5, then converts them. That boundary needs to be explicit.&lt;/p&gt;

&lt;p&gt;The fixed-fee assumption matters too: one item per transaction. A multi-item order needs its order-level fee allocated across the items. Shipping, tax, failed output, and material allowance also need named assumptions rather than hidden defaults.&lt;/p&gt;

&lt;p&gt;The free &lt;a href="https://wizekin.web.app/craftcost/" rel="noopener noreferrer"&gt;CraftCost Studio&lt;/a&gt; includes a complete batch example and separates labor cost from the profit remaining after the entered costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Use the right stock figure
&lt;/h2&gt;

&lt;p&gt;A simple reorder point is average daily demand multiplied by supplier lead time, plus safety stock. But comparing it only with stock on the shelf can ignore an incoming shipment or reserved units.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reorderPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dailyDemand&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;leadDays&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;safetyStock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inventoryPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;onHand&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;onOrder&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;allocated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldReorder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inventoryPosition&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;reorderPoint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With demand of four units per day, seven lead days, and ten safety units, the reorder point is 38. If there are 25 units on hand, ten incoming, and five allocated, position is 30.&lt;/p&gt;

&lt;p&gt;An order quantity needs another decision: the target coverage. Seven extra days gives a target of &lt;code&gt;4 * (7 + 7) + 10&lt;/code&gt;, or 66. This model suggests 36 units when the reorder condition is met.&lt;/p&gt;

&lt;p&gt;The useful tests include equality at the reorder threshold, zero demand, and allocations exceeding on-hand stock. Zero demand should produce an explicit “undefined” stock-cover result, not an infinite-looking number that reads like a recommendation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wizekin.web.app/stocksimple/" rel="noopener noreferrer"&gt;StockSimple Studio&lt;/a&gt; exposes each assumption. It is a planning calculator, not a demand forecast or an accounting valuation service.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Generate the question and answer together
&lt;/h2&gt;

&lt;p&gt;For exact-division practice, rejection-sampling random dividends until they happen to divide evenly is unnecessary. Choose a nonzero divisor and a quotient, then construct the dividend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;divisor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dividend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;divisor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;quotient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 80&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dividend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;divisor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;quotient&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The range now describes divisor and quotient. The dividend can be larger, which the UI needs to explain.&lt;/p&gt;

&lt;p&gt;Each question object contains its answer. Both the worksheet and the answer page render from the same objects. A seeded random generator makes a sheet reproducible from its settings, while changing the seed produces another sequence. Repeated questions can still occur; deterministic does not mean unique.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wizekin.web.app/lessonsheet/" rel="noopener noreferrer"&gt;LessonSheet Studio&lt;/a&gt; uses this approach for printable arithmetic practice and separate answer pages. It does not collect student records or claim curriculum certification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the calculations independent of the page
&lt;/h2&gt;

&lt;p&gt;All three tools put calculation functions in a shared module that Node can test without loading a browser. Useful assertions check identities: the calculated craft profit has the intended margin; inventory position reconciles; every exact-division question satisfies &lt;code&gt;dividend === divisor * answer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Browser testing then covers the things those assertions cannot: reset controls, labels, saved-state behavior, and narrow-screen layouts. In this release, browser testing caught a reset control shadowing &lt;code&gt;form.reset&lt;/code&gt;, and a note field that was accidentally required. Passing arithmetic tests did not catch either issue.&lt;/p&gt;

&lt;p&gt;Maker disclosure: these are Wizekin tools, developed with AI assistance. The public tools are free. Separate offline workspace editions have been prepared, but their paid listings are not live at publication time. There are no traffic, income, or maintenance guarantees.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>testing</category>
    </item>
    <item>
      <title>How I Break Down a Freelance Website Quote Before Naming a Price</title>
      <dc:creator>Mohamed Ghanem</dc:creator>
      <pubDate>Thu, 22 Oct 2026 11:30:55 +0000</pubDate>
      <link>https://dev.to/wizekin/how-i-break-down-a-freelance-website-quote-before-naming-a-price-49ne</link>
      <guid>https://dev.to/wizekin/how-i-break-down-a-freelance-website-quote-before-naming-a-price-49ne</guid>
      <description>&lt;h1&gt;
  
  
  How I Break Down a Freelance Website Quote Before Naming a Price
&lt;/h1&gt;

&lt;p&gt;It's surprisingly easy to quote a freelance website by looking at its page count and multiplying by a number you found online. The problem: two five-page websites can represent very different amounts of work.&lt;/p&gt;

&lt;p&gt;A brochure site with client-provided copy isn't the same project as a site with custom forms, integrations, content migration and an uncertain approval process.&lt;/p&gt;

&lt;p&gt;A better starting point is to &lt;strong&gt;estimate the work you actually intend to deliver&lt;/strong&gt; and put the assumptions in writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Turn the vague request into a scope
&lt;/h2&gt;

&lt;p&gt;Before naming a price, write down what "a website" actually means.&lt;/p&gt;

&lt;p&gt;For a small brochure website, that might include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Five responsive pages with agreed layouts.&lt;/li&gt;
&lt;li&gt;The client supplies final copy and images.&lt;/li&gt;
&lt;li&gt;One contact form with basic validation.&lt;/li&gt;
&lt;li&gt;Testing in a small, documented set of target browsers.&lt;/li&gt;
&lt;li&gt;Two rounds of revisions on the approved design.&lt;/li&gt;
&lt;li&gt;Launch to an agreed hosting environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then write down what's &lt;strong&gt;not&lt;/strong&gt; included: logo design, copywriting, monthly maintenance, paid plugins and new pages after scope approval.&lt;/p&gt;

&lt;p&gt;This is not needless paperwork. It is how you distinguish an estimate for specific work from a promise to do anything a client later imagines.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Estimate hours, not just pages
&lt;/h2&gt;

&lt;p&gt;Here's an illustrative task estimate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Work&lt;/th&gt;
&lt;th&gt;Hours&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Five pages, 3 hours per page&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discovery and project setup&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing and launch&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expected revision work&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Estimated total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 25 hours are an example, not a standard workload. A developer using reusable components may take less time. A custom design with complex interactions may take much longer.&lt;/p&gt;

&lt;p&gt;Choose an internal hourly planning rate that covers your earning goals and real business costs. For this example only, use &lt;strong&gt;$45/hour&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Labor estimate: &lt;strong&gt;25 × $45 = $1,125&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Separate direct costs from the price of your time
&lt;/h2&gt;

&lt;p&gt;Suppose this project also needs $75 in project-specific expenses.&lt;/p&gt;

&lt;p&gt;Now the base estimate is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Labor: $1,125&lt;/li&gt;
&lt;li&gt;Direct expenses: $75&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Base: $1,200&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you add a 10% contingency to address foreseeable estimation uncertainty, that's another $120, bringing the illustrative total to &lt;strong&gt;$1,320 before any applicable taxes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A contingency isn't guaranteed profit, and it shouldn't silently substitute for a clear scope. Your agreement should explain what you're actually charging and delivering.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Make the payment terms concrete
&lt;/h2&gt;

&lt;p&gt;An estimated project price isn't yet a usable quote.&lt;/p&gt;

&lt;p&gt;Say you agree on a &lt;strong&gt;30% upfront deposit&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total project price: $1,320&lt;/li&gt;
&lt;li&gt;Deposit on acceptance: $396&lt;/li&gt;
&lt;li&gt;Remaining balance: $924&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The deposit is &lt;strong&gt;part of the $1,320 total&lt;/strong&gt;. It isn't a surcharge. Also spell out when the balance becomes due and what happens if the project is delayed or canceled.&lt;/p&gt;

&lt;p&gt;A one-line quote such as "website — $1,320" leaves too many questions unanswered.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Write a change-request rule before you need one
&lt;/h2&gt;

&lt;p&gt;Imagine the project is approved and the client asks for two additional pages.&lt;/p&gt;

&lt;p&gt;Instead of treating the new pages as automatically included, use a simple process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Describe the requested change.&lt;/li&gt;
&lt;li&gt;Estimate the additional time, cost and schedule impact.&lt;/li&gt;
&lt;li&gt;Ask for agreement on the change.&lt;/li&gt;
&lt;li&gt;Begin the extra work after approval.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is easier for both parties when the original scope specified five pages and a finite number of revision rounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A tiny calculator in JavaScript
&lt;/h2&gt;

&lt;p&gt;The arithmetic can be expressed as a pure function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;estimateWebsite&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hoursPerPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setupHours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testingHours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;revisionHours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hourlyRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expenses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;contingencyPct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;depositPct&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;hoursPerPage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;setupHours&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;testingHours&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;revisionHours&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;labor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;hourlyRate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;labor&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;expenses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;contingencyPct&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;depositPct&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;labor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;deposit&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Illustrative result:&lt;/span&gt;
&lt;span class="c1"&gt;// 25 hours, $1,125 labor, $1,320 total,&lt;/span&gt;
&lt;span class="c1"&gt;// $396 deposit, $924 remaining.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a real application, also validate every input, handle currency formatting and distinguish fixed fees from percentages. Taxes, if applicable, need to be treated according to the actual agreement and local requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Before you send the quote
&lt;/h2&gt;

&lt;p&gt;I would check these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can the client verify what's included and excluded?&lt;/li&gt;
&lt;li&gt;Are the assumptions about content, access and approvals clear?&lt;/li&gt;
&lt;li&gt;Have you included testing, meetings and revision time?&lt;/li&gt;
&lt;li&gt;Is the change-request process explicit?&lt;/li&gt;
&lt;li&gt;Does the payment schedule describe the full agreed price?&lt;/li&gt;
&lt;li&gt;Have you considered whether an hourly agreement with a budget cap would suit uncertain work better?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to experiment with your own assumptions, I built a &lt;strong&gt;&lt;a href="https://wizekin.web.app/clearquote/guides/website-project-pricing-calculator.html" rel="noopener noreferrer"&gt;free website project pricing calculator&lt;/a&gt;&lt;/strong&gt;. It estimates hours, labor, expenses, contingency, taxes if applicable and deposits in the browser without signup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I'm the maker of ClearQuote Studio, which hosts the free calculator and an optional paid quote/invoice toolkit. This post is educational, and the rates are illustrative—not a claim about typical web-development prices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question for other freelancers:&lt;/strong&gt; Which part of scoping a website most often causes you to underestimate the work?&lt;/p&gt;

</description>
      <category>freelancing</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
