import { showConfirmDialog } from '../confirm-dialog/confirm-dialog.js'; interface Project { id: string; name: string; owner_id: string; } interface ProjectMember { id: string; project_id: string; member_type: 'user' | 'group'; member_id: string; role: string; } class ProjectEditor extends HTMLElement { connectedCallback(): void { this.render(); } async render(): Promise { const res = await fetch('/api/projects'); const projects = await res.json() as Project[]; this.innerHTML = `

Projects

`; this.querySelector('.create-form')!.addEventListener('submit', async (e: Event) => { e.preventDefault(); const form = e.target as HTMLFormElement; const name = (form.elements.namedItem('name') as HTMLInputElement).value.trim(); const res = await fetch('/api/projects', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name }) }); if (res.ok) this.render(); }); this.querySelectorAll('.btn-delete').forEach(btn => { btn.addEventListener('click', async ( e ) => { console.log( "Clicking:", e ); const el = btn as HTMLElement; const ok = await showConfirmDialog({ icon: '🗑', title: 'Delete Project', message: `Delete "${el.dataset.name}"? This cannot be undone.`, confirmLabel: 'Delete', cancelLabel: 'Cancel', danger: true }); console.log( "Result:", ok ); if (!ok) return; await fetch(`/api/projects/${el.dataset.id}`, { method: 'DELETE' }); this.render(); }); }); this.querySelectorAll('.btn-members').forEach(btn => { btn.addEventListener('click', () => this.toggleMembers((btn as HTMLElement).dataset.id!)); }); } async toggleMembers(projectId: string): Promise { const panel = this.querySelector(`.members-panel[data-project="${projectId}"]`) as HTMLElement; if (panel.style.display !== 'none') { panel.style.display = 'none'; return; } panel.style.display = 'block'; await this.loadMembers(projectId, panel); } async loadMembers(projectId: string, panel: HTMLElement): Promise { const res = await fetch(`/api/projects/${projectId}/members`); const members = await res.json() as ProjectMember[]; panel.innerHTML = `
    ${members.map(m => `
  • ${m.member_type}: ${m.member_id} — ${m.role}
  • `).join('') || '
  • No members
  • '}
`; panel.querySelectorAll('.btn-remove-member').forEach(btn => { btn.addEventListener('click', async () => { const el = btn as HTMLElement; await fetch(`/api/projects/${el.dataset.pid}/members/${el.dataset.mid}`, { method: 'DELETE' }); await this.loadMembers(projectId, panel); }); }); (panel.querySelector('.add-member-form') as HTMLFormElement).addEventListener('submit', async (e: Event) => { e.preventDefault(); const data = Object.fromEntries(new FormData(e.target as HTMLFormElement)); await fetch(`/api/projects/${projectId}/members`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); await this.loadMembers(projectId, panel); }); } } customElements.define('project-editor', ProjectEditor);