5d60d33db1
Volledige Foodlinkk Command Center uitbreiding met social automatisering, reclamefolder filters, Proxmox monitoring en documentatie.
56 lines
3.0 KiB
HTML
56 lines
3.0 KiB
HTML
{% extends "base.html" %}
|
||
{% block content %}
|
||
<div x-data="clientsCrud()">
|
||
<header class="page-header"><h1>Clients</h1>
|
||
<p class="subtitle page-tip">Kanban by stage — click a card for details or change stage from the dropdown.</p></header>
|
||
<button class="btn btn-primary" @click="openModal()">Add client</button>
|
||
<div class="kanban">
|
||
{% set stages = ['intake','discovery','proposal','active','churned'] %}
|
||
{% for st in stages %}
|
||
<div class="kanban-col"><h3>{{ st }}</h3>
|
||
{% for c in clients if c.stage == st %}
|
||
<div class="kanban-card clickable-row" @click="show({{ c.id }}, '{{ c.name|e }}', '{{ (c.email or '')|e }}', '{{ c.stage|e }}', '{{ (c.notes or '')|e }}')">
|
||
<strong>{{ c.name }}</strong><br/><small>{{ c.sector or '' }}</small>
|
||
<select class="form-input" @click.stop="" @change="setStage({{ c.id }}, $event.target.value, '{{ c.name|e }}', '{{ (c.email or '')|e }}', '{{ (c.notes or '')|e }}')">
|
||
{% for s in stages %}<option value="{{ s }}" {% if c.stage==s %}selected{% endif %}>{{ s }}</option>{% endfor %}
|
||
</select>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
<div class="modal" :class="{ open: modal }" @click.self="modal=false">
|
||
<div class="modal-card"><h3 x-text="form.id ? 'Edit client' : 'New client'"></h3>
|
||
<input class="form-input" placeholder="Name" x-model="form.name" />
|
||
<input class="form-input" placeholder="Email" x-model="form.email" />
|
||
<select x-model="form.stage" class="form-input"><option>intake</option><option>discovery</option><option>proposal</option><option>active</option><option>churned</option></select>
|
||
<textarea class="form-input" x-model="form.notes" placeholder="Notes"></textarea>
|
||
<div class="btn-group"><button class="btn btn-primary" @click="save()">Save</button><button class="btn btn-secondary" @click="modal=false">Cancel</button></div>
|
||
</div>
|
||
</div>
|
||
<aside class="drawer" :class="{ open: drawer }"><button class="drawer-close" @click="drawer=false">×</button><p x-text="detail"></p></aside>
|
||
</div>
|
||
{% endblock %}
|
||
{% block scripts %}
|
||
<script>
|
||
function clientsCrud() {
|
||
return {
|
||
modal: false, drawer: false, detail: '',
|
||
form: { id: null, name: '', email: '', stage: 'intake', notes: '' },
|
||
openModal() { this.form = { id: null, name: '', email: '', stage: 'intake', notes: '' }; this.modal = true; },
|
||
show(id, name, email, stage, notes) { this.detail = name + ' · ' + email; this.form = { id, name, email, stage, notes }; this.drawer = true; },
|
||
async save() {
|
||
const body = { name: this.form.name, email: this.form.email, stage: this.form.stage, notes: this.form.notes };
|
||
if (this.form.id) await Cockpit.api('/clients/' + this.form.id, { method: 'PUT', body: JSON.stringify(body) });
|
||
else await Cockpit.api('/clients', { method: 'POST', body: JSON.stringify(body) });
|
||
location.reload();
|
||
},
|
||
async setStage(id, stage, name, email, notes) {
|
||
await Cockpit.api('/clients/' + id, { method: 'PUT', body: JSON.stringify({ name, email, stage, notes }) });
|
||
Cockpit.toast('Stage updated', 'success'); location.reload();
|
||
}
|
||
};
|
||
}
|
||
</script>
|
||
{% endblock %}
|