- Neues Projekt (Projekte-Seite): Repo-Name blieb nach dem ersten
Buchstaben der Subdomain stehen ("m" statt "musterfirma")
- Ticket "Projekt waehlen": archivierte Repos nach Flag ausblenden, nicht
nach status (reaktivierte fehlten, archivierte wurden angeboten)
- Projektliste: "Aktive Projekte" + neue Ansicht "Alle inkl. Archiv";
Liste wird auch nach einem Anlege-Fehler neu geladen
- Kundenauswahl: "Kein Kunde" entfernt Kunde und Ticket wirklich (mit
Rueckfrage); beim Kundenwechsel bleibt kein fremdes Ticket haengen
- Zuordnen-Assistent ueberschreibt eine vorhandene Website nicht mehr
- Neues Projekt am Ticket bekommt die Art Website
- Umlaute in Subdomains wie im Portal (mueller statt m-ller)
- Preview-Block nur mit gespeicherter Subdomain; archivierte Projekte
erst reaktivieren, bevor sie bearbeitet werden
- Repo-Import beim Aufklappen hoechstens einmal pro Minute
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
77 lines
2.5 KiB
JavaScript
77 lines
2.5 KiB
JavaScript
import { useState, useCallback } from 'react'
|
|
import { databases, DATABASE_ID, COLLECTIONS, Query } from '../lib/appwrite'
|
|
import { assignWebsiteProject } from '../lib/projectAdminApi'
|
|
import { assignSequentially } from '../lib/projectAssign'
|
|
|
|
export function useWebsiteProjects() {
|
|
const [projects, setProjects] = useState([])
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState(null)
|
|
|
|
const fetchAllProjects = useCallback(async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
try {
|
|
const response = await databases.listDocuments(
|
|
DATABASE_ID, COLLECTIONS.WEBSITE_PROJECTS,
|
|
[Query.orderDesc('$createdAt'), Query.limit(500)]
|
|
)
|
|
setProjects(response.documents)
|
|
return response.documents
|
|
} catch (err) {
|
|
setError(err.message)
|
|
return []
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}, [])
|
|
|
|
const fetchByTicketId = useCallback(async (ticketId) => {
|
|
if (!ticketId) return []
|
|
try {
|
|
const response = await databases.listDocuments(
|
|
DATABASE_ID, COLLECTIONS.WEBSITE_PROJECTS,
|
|
[Query.equal('ticketId', ticketId), Query.limit(100)]
|
|
)
|
|
return response.documents
|
|
} catch {
|
|
return []
|
|
}
|
|
}, [])
|
|
|
|
const assignProjects = async (projectIds, ctx) => {
|
|
const results = await assignSequentially(projectIds, ctx, assignWebsiteProject)
|
|
const success = results.every((r) => r.ok)
|
|
const firstError = results.find((r) => !r.ok)
|
|
return { success, error: firstError?.error, results }
|
|
}
|
|
|
|
// Nur vom Ticket loesen: customerId bleibt, sonst verliert der Kunde die Vorschau im Portal
|
|
const unassignProject = async (projectId) => {
|
|
try {
|
|
await databases.updateDocument(
|
|
DATABASE_ID, COLLECTIONS.WEBSITE_PROJECTS, projectId,
|
|
{ ticketId: '', updatedAt: new Date().toISOString() }
|
|
)
|
|
return { success: true }
|
|
} catch (err) {
|
|
return { success: false, error: err.message }
|
|
}
|
|
}
|
|
|
|
// Projektliste "Kein Kunde": Kunde UND Ticket entfernen (bewusste Auswahl, mit Rueckfrage)
|
|
const clearCustomer = async (projectId) => {
|
|
try {
|
|
await databases.updateDocument(
|
|
DATABASE_ID, COLLECTIONS.WEBSITE_PROJECTS, projectId,
|
|
{ customerId: '', ticketId: '', updatedAt: new Date().toISOString() }
|
|
)
|
|
return { success: true }
|
|
} catch (err) {
|
|
return { success: false, error: err.message }
|
|
}
|
|
}
|
|
|
|
return { projects, loading, error, fetchAllProjects, fetchByTicketId, assignProjects, unassignProject, clearCustomer }
|
|
}
|