Kunden-Dashboard: - Tab-Navigation: Projekte | Was wurde gemacht | Rechnungen | Chat - Projekt-Details pro Projekt: letzte Git-Commits (Titel+Beschreibung), Projektgroesse, Datei-Uebersicht (Top-Level aggregiert), Ticket-Arbeiten - Rechnungen: gestylte Liste mit Status-Pillen, Ansehen/Zahlen-Link, PDF-Download ueber Server-Proxy (IDOR-geschuetzt) - Chat mit dem Webklar-Team (Polling, Ungelesen-Badge, viewAs blockiert) Admin-Dashboard: - Chat-Tab: Konversationsliste + Thread + Antwortfeld, Ungelesen-Badge Backend: - giteaAdmin: getRepoInfo, listRepoCommits, getRepoTreeSummary - projectInsights: 5-min-Cache, Invalidierung per Gitea-Webhook - /api/projects/:id/git|files|work mit Ownership-Check (404) - /api/chat/* (Kunde) + /api/portal-admin/chats/* (Admin), portalMessages-Collection - mailer: E-Mail-Benachrichtigung an Admins bei Kundennachricht (15-min-Throttle) - gitWorksheet: dd.mm.yyyy, voller Commit-Body, startTime leer (Zeit-Nachtrag), Auto-Webpage-Ticket bei Push auf Projekt ohne Ticket (ensureProjectTicket) - customerActivity: Git-Push-Eintraege fuer Kunden sichtbar Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
61 lines
2.0 KiB
JavaScript
61 lines
2.0 KiB
JavaScript
import { config } from '../config.js'
|
|
import { listDocuments, Query } from './appwriteAdmin.js'
|
|
|
|
/**
|
|
* Tickets + zugehoerige Worksheets eines Kunden ("was wurde gemacht").
|
|
* excludeTypes: Ticket-Typen, die der Kunde nicht sehen soll (z. B. Akquise).
|
|
*/
|
|
export async function getCustomerActivity(customerId, { ticketLimit = 25, excludeTypes = [] } = {}) {
|
|
if (!customerId) return []
|
|
|
|
let workorders = await listDocuments(config.collections.workorders, [
|
|
Query.equal('customerId', customerId),
|
|
Query.orderDesc('$createdAt'),
|
|
Query.limit(ticketLimit),
|
|
])
|
|
|
|
if (excludeTypes.length) {
|
|
const blocked = new Set(excludeTypes.map((t) => t.toLowerCase()))
|
|
workorders = workorders.filter((w) => !blocked.has(String(w.type || '').toLowerCase()))
|
|
}
|
|
|
|
const ids = workorders.map((w) => w.$id)
|
|
let worksheets = []
|
|
if (ids.length) {
|
|
worksheets = await listDocuments(config.collections.worksheets, [
|
|
Query.equal('workorderId', ids),
|
|
Query.orderDesc('$createdAt'),
|
|
Query.limit(300),
|
|
]).catch(() => [])
|
|
}
|
|
|
|
const sheetsByWorkorder = {}
|
|
for (const ws of worksheets) {
|
|
// Git-Push-Eintraege dem Kunden sofort zeigen, sonstige reine Kommentare nicht
|
|
if (ws.isComment && ws.serviceType !== 'GIT') continue
|
|
const list = (sheetsByWorkorder[ws.workorderId] ||= [])
|
|
list.push({
|
|
wsid: ws.wsid || '',
|
|
employeeName: ws.employeeName || ws.employeeShort || '',
|
|
serviceType: ws.serviceType || '',
|
|
newStatus: ws.newStatus || '',
|
|
totalTime: ws.totalTime || '',
|
|
date: ws.endDate || ws.startDate || '',
|
|
details: ws.details || '',
|
|
isGit: ws.serviceType === 'GIT',
|
|
pending: ws.serviceType === 'GIT' && !ws.startTime,
|
|
createdAt: ws.createdAt || ws.$createdAt || '',
|
|
})
|
|
}
|
|
|
|
return workorders.map((w) => ({
|
|
id: w.$id,
|
|
woid: w.woid || '',
|
|
topic: w.topic || w.title || '',
|
|
status: w.status || '',
|
|
type: w.type || '',
|
|
createdAt: w.createdAt || w.$createdAt || '',
|
|
worksheets: (sheetsByWorkorder[w.$id] || []).slice(0, 20),
|
|
}))
|
|
}
|