diff options
Diffstat (limited to 'app/templates')
| -rw-r--r-- | app/templates/base.html | 5 | ||||
| -rw-r--r-- | app/templates/household.html | 106 | ||||
| -rw-r--r-- | app/templates/shopping_list.html | 11 |
3 files changed, 121 insertions, 1 deletions
diff --git a/app/templates/base.html b/app/templates/base.html index b58ef64..6702474 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -40,6 +40,11 @@ <i class="bi bi-cart me-1"></i>Shopping List </a> </li> + <li class="nav-item"> + <a class="nav-link {% if request.endpoint == 'household' %}active{% endif %}" href="/household"> + <i class="bi bi-people me-1"></i>Household + </a> + </li> </ul> <ul class="navbar-nav ms-auto gap-1 align-items-center"> diff --git a/app/templates/household.html b/app/templates/household.html new file mode 100644 index 0000000..cbb5121 --- /dev/null +++ b/app/templates/household.html @@ -0,0 +1,106 @@ +{% extends "base.html" %} +{% block title %}Household — Menu Planner{% endblock %} + +{% block content %} +<div class="d-flex align-items-center justify-content-between mb-4"> + <div> + <h1 class="h3 fw-bold mb-0"><i class="bi bi-people me-2"></i>Household</h1> + {% if household %}<p class="text-muted mb-0">{{ household.name }}</p>{% endif %} + </div> +</div> + +{% if not household %} +<div class="card shadow-sm"> + <div class="card-body text-center py-5"> + <i class="bi bi-house-add fs-1 text-muted mb-3 d-block"></i> + <h5 class="fw-semibold">You're not in a household yet</h5> + <p class="text-muted">Create one and invite family members.<br> + Shopping lists will automatically combine everyone's meal plans.</p> + <form method="POST" action="/household/create" class="d-inline-flex gap-2 mt-2"> + <input type="text" name="name" class="form-control form-control-sm" + placeholder="e.g. The Smith Family" style="width:230px"> + <button type="submit" class="btn btn-primary btn-sm"> + <i class="bi bi-plus-circle me-1"></i>Create Household + </button> + </form> + </div> +</div> + +{% else %} + +<!-- Members --> +<div class="card shadow-sm mb-4"> + <div class="card-header fw-semibold d-flex align-items-center gap-2"> + <i class="bi bi-people-fill"></i> Members + <span class="badge bg-secondary ms-auto">{{ members|length }}</span> + </div> + <ul class="list-group list-group-flush"> + {% for m in members %} + <li class="list-group-item d-flex align-items-center justify-content-between"> + <div class="d-flex align-items-center gap-2"> + <i class="bi bi-person-circle text-muted fs-5"></i> + <span class="fw-semibold">{{ m.username }}</span> + {% if m.id == household.owner_id %} + <span class="badge bg-warning text-dark">Owner</span> + {% endif %} + {% if m.is_me %} + <span class="text-muted small">(you)</span> + {% endif %} + </div> + {% if is_owner and not m.is_me %} + <form method="POST" action="/household/remove" + onsubmit="return confirm('Remove {{ m.username }} from the household?')"> + <input type="hidden" name="username" value="{{ m.username }}"> + <button type="submit" class="btn btn-sm btn-outline-danger"> + <i class="bi bi-person-dash me-1"></i>Remove + </button> + </form> + {% endif %} + </li> + {% endfor %} + </ul> +</div> + +{% if is_owner %} +<!-- Invite --> +<div class="card shadow-sm mb-4"> + <div class="card-header fw-semibold"> + <i class="bi bi-person-plus me-1"></i>Invite Member + </div> + <div class="card-body"> + <form method="POST" action="/household/invite" class="d-flex gap-2"> + <input type="text" name="username" class="form-control" placeholder="Username" required autocomplete="off"> + <button type="submit" class="btn btn-primary">Add</button> + </form> + <p class="text-muted small mt-2 mb-0"> + The user must already have an account. They'll join immediately and their meal plan + will be included in your combined shopping list. + </p> + </div> +</div> +{% endif %} + +<!-- Leave / dissolve --> +<div class="card shadow-sm border-danger border-opacity-25"> + <div class="card-body"> + {% if is_owner and members|length > 1 %} + <p class="text-muted small mb-2"> + Remove all other members before you can dissolve the household. + </p> + <button class="btn btn-outline-danger btn-sm" disabled> + <i class="bi bi-box-arrow-left me-1"></i>Dissolve Household + </button> + {% else %} + <form method="POST" action="/household/leave" + onsubmit="return confirm('{% if is_owner %}Dissolve this household?{% else %}Leave this household?{% endif %}')"> + <button type="submit" class="btn btn-outline-danger btn-sm"> + <i class="bi bi-box-arrow-left me-1"></i> + {% if is_owner %}Dissolve Household{% else %}Leave Household{% endif %} + </button> + </form> + {% endif %} + </div> +</div> + +{% endif %} +{% endblock %} diff --git a/app/templates/shopping_list.html b/app/templates/shopping_list.html index e6cfaaf..8a3a60e 100644 --- a/app/templates/shopping_list.html +++ b/app/templates/shopping_list.html @@ -9,6 +9,9 @@ Week of {{ week_start.strftime('%B %d, %Y') }} {% if total %} · {{ checked }}/{{ total }} checked{% endif %} </p> + {% if member_count and member_count > 1 %} + <p class="text-muted small mb-0"><i class="bi bi-people me-1"></i>Combined from {{ member_count }} household members' plans</p> + {% endif %} </div> <div class="d-flex gap-2 align-items-center"> <a href="/shopping-list?week={{ prev_week }}" class="btn btn-outline-secondary btn-sm"><i class="bi bi-chevron-left"></i></a> @@ -145,7 +148,13 @@ async function regenerate() { if (!res) return; const data = await res.json(); if (data.success) { - location.reload(); + if (data.member_count > 1) { + document.getElementById('toastBody').textContent = `Combined from ${data.member_count} members' plans!`; + toast.show(); + setTimeout(() => location.reload(), 1500); + } else { + location.reload(); + } } else { document.getElementById('toastBody').textContent = data.error || 'No meals planned for this week.'; document.getElementById('toast').className = 'toast align-items-center text-bg-danger border-0'; |
