{% extends "base.html" %}
{% block title %}{{ "Edit" if mode == "edit" else "New" }} Project{% endblock %}
{% block page_class %}has-sticky-actions{% endblock %}
{% block content %}
<div class="header-row">
<div>
<h1>{{ "Edit" if mode == "edit" else "New" }} Project</h1>
{% if mode == "edit" %}
<p class="muted">{{ project.project_number }}</p>
{% endif %}
</div>
</div>
<section class="section" style="margin-top:10px;">
{% if project.errors %}
<div class="alert error">
{% for error in project.errors %}
<div>{{ error }}</div>
{% endfor %}
</div>
{% endif %}
<form method="post" action="{{ '/edit/' ~ project.id if mode == 'edit' else '/create' }}" id="project-form">
<div class="grid-2">
<div class="field">
<label for="customer_name">Customer Name</label>
<input id="customer_name" name="customer_name" value="{{ project.customer_name }}" required>
</div>
<div class="field">
<label for="customer_email">Customer Email</label>
<input id="customer_email" name="customer_email" type="email" value="{{ project.customer_email }}">
</div>
</div>
<h2>Line Items</h2>
<div id="line-items">
{% set single_line_item = project.line_items|length <= 1 %}
{% for item in project.line_items %}
<div class="line-item">
<div class="line-item-text">
<label>Description</label>
<textarea name="item_name" rows="5" required>{{ item.name }}</textarea>
</div>
<div class="line-item-price">
<label>Price</label>
<input name="item_price" inputmode="decimal" value="{{ item.price_input if item.price_input is defined else '%.2f'|format((item.amount_cents or 0) / 100) }}" required>
</div>
<button class="secondary danger" type="button" data-remove-line {% if single_line_item %}hidden{% endif %}>Remove</button>
</div>
{% endfor %}
</div>
<button class="secondary add-line-button" type="button" id="add-line">Add Another</button>
<div class="stats">
<div class="stat">
<span>Total</span>
<strong id="form-total">{{ 0|money(currency) }}</strong>
</div>
</div>
<div class="field">
<label for="scope_terms">Scope / Terms</label>
<textarea id="scope_terms" name="scope_terms" rows="7">{{ project.scope_terms }}</textarea>
</div>
<div class="sticky-actions">
<div class="sticky-actions-inner">
{% if mode == "edit" %}
<a class="button secondary" href="/project/{{ project.id }}">Back</a>
{% else %}
<a class="button secondary" href="/">Cancel</a>
{% endif %}
<button type="submit">{{ "Save Project" if mode == "edit" else "Create Project" }}</button>
</div>
</div>
</form>
</section>
<script>
const lineItems = document.getElementById("line-items");
const addLine = document.getElementById("add-line");
const total = document.getElementById("form-total");
const currency = "{{ currency }}";
function money(cents) {
return `${currency} ${(cents / 100).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}`;
}
function recalc() {
let cents = 0;
lineItems.querySelectorAll('input[name="item_price"]').forEach((input) => {
const parsed = Number(String(input.value).replace(/[$,]/g, ""));
if (!Number.isNaN(parsed)) cents += Math.round(parsed * 100);
});
total.textContent = money(cents);
}
function bindRemove(button) {
button.addEventListener("click", () => {
if (lineItems.querySelectorAll(".line-item").length <= 1) return;
button.closest(".line-item").remove();
updateRemoveButtons();
recalc();
});
}
function updateRemoveButtons() {
const rows = lineItems.querySelectorAll(".line-item");
rows.forEach((row) => {
const button = row.querySelector("[data-remove-line]");
button.hidden = rows.length <= 1;
});
}
addLine.addEventListener("click", () => {
const row = lineItems.querySelector(".line-item").cloneNode(true);
row.querySelectorAll("input, textarea").forEach((input) => input.value = "");
bindRemove(row.querySelector("[data-remove-line]"));
row.querySelectorAll("input").forEach((input) => input.addEventListener("input", recalc));
lineItems.appendChild(row);
row.querySelector("textarea").focus();
updateRemoveButtons();
recalc();
});
lineItems.querySelectorAll("[data-remove-line]").forEach(bindRemove);
lineItems.querySelectorAll("input").forEach((input) => input.addEventListener("input", recalc));
updateRemoveButtons();
recalc();
</script>
{% endblock %}