Authenticated Task Manager
A page that requires login and displays tasks assigned to the current user with complete/dismiss actions.
from abstra.pages import register_function, get_user
from abstra.tables import select, update
@register_function
def get_my_tasks():
user = get_user()
tasks = select("tasks", where={"assignee_email": user.email, "status": "pending"})
return [{"id": t["id"], "title": t["title"], "due": str(t["due_date"]), "priority": t.get("priority","medium")} for t in tasks]
@register_function
def complete_task(task_id: str):
user = get_user()
update("tasks", where={"id": task_id}, set={"status": "done", "completed_by": user.email})
return {"ok": True}
@register_function
def __render__():
user = get_user()
return f"""
<script src="https://cdn.tailwindcss.com"></script>
<style>body {{ margin:0; font-family:'Inter',system-ui,sans-serif; background:#f8fafc; }}</style>
<div class="min-h-screen p-8 max-w-2xl mx-auto">
<div class="flex items-center justify-between mb-8">
<div>
<h1 class="text-2xl font-bold text-slate-800">My Tasks</h1>
<p class="text-sm text-slate-400 mt-1">Logged in as <span class="font-medium text-slate-500">{user.email}</span></p>
</div>
<div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-700 font-bold text-sm">
{user.email[0].upper()}
</div>
</div>
<div id="tasks">
<div class="flex justify-center py-12"><div class="animate-spin w-6 h-6 border-2 border-indigo-600 border-t-transparent rounded-full"></div></div>
</div>
</div>
<script>
const priorities = {{ high:'rose', medium:'amber', low:'slate' }};
async function load() {{
const tasks = await get_my_tasks();
const el = document.getElementById('tasks');
if (!tasks.length) {{
el.innerHTML = `<div class="text-center py-16">
<div class="w-16 h-16 rounded-full bg-emerald-50 flex items-center justify-center mx-auto mb-4">
<svg class="w-8 h-8 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
</div>
<p class="text-slate-500 font-medium">All caught up!</p>
<p class="text-sm text-slate-400 mt-1">No pending tasks for you</p>
</div>`;
return;
}}
el.innerHTML = '<div class="space-y-3">' + tasks.map(t => {{
const c = priorities[t.priority] || 'slate';
return `<div class="bg-white rounded-xl p-5 border border-slate-100 shadow-sm hover:shadow-md transition-all group">
<div class="flex items-start justify-between">
<div class="flex-1">
<div class="flex items-center gap-2 mb-1">
<span class="w-2 h-2 rounded-full bg-${{c}}-500"></span>
<span class="text-xs font-medium text-${{c}}-600 uppercase">${{t.priority}}</span>
</div>
<p class="font-medium text-slate-800">${{t.title}}</p>
<p class="text-xs text-slate-400 mt-1">Due ${{t.due}}</p>
</div>
<button onclick="done('${{t.id}}')"
class="opacity-0 group-hover:opacity-100 transition-opacity bg-emerald-50 hover:bg-emerald-100 text-emerald-700 text-sm font-medium px-4 py-2 rounded-lg">
Complete
</button>
</div>
</div>`;
}}).join('') + '</div>';
}}
async function done(id) {{ await complete_task(id); load(); }}
load();
</script>
"""
Key patterns: get_user() in __render__ and functions, priority badges, hover-reveal action buttons, empty state with icon.