diff --git a/src/components/TicketCard.jsx b/src/components/TicketCard.jsx index 5e1235a..4d6d085 100644 --- a/src/components/TicketCard.jsx +++ b/src/components/TicketCard.jsx @@ -8,6 +8,7 @@ import EditorDropdown from './EditorDropdown' import CreateWorksheetModal from './CreateWorksheetModal' import StatusHistoryModal from './StatusHistoryModal' import WorksheetList from './WorksheetList' +import WorksheetTimesModal from './WorksheetTimesModal' import WorksheetStats from './WorksheetStats' import TicketAssignedProjectsPanel from './TicketAssignedProjectsPanel' import TicketProjectsModal from './TicketProjectsModal' @@ -19,6 +20,7 @@ import Tabs from './ui/Tabs' import Badge from './ui/Badge' import { StatusPill, PriorityPill } from './ui/StatusPill' import { useWorksheets } from '../hooks/useWorksheets' +import { useAuth } from '../context/AuthContext' import { databases, DATABASE_ID, COLLECTIONS } from '../lib/appwrite' import { serviceTypeLabel } from '../lib/ticketForm' @@ -31,14 +33,16 @@ const TABS = [ ] export default function TicketCard({ ticket, onUpdate }) { + const { user } = useAuth() const [expanded, setExpanded] = useState(false) const [activeTab, setActiveTab] = useState('details') const [showCreateWorksheet, setShowCreateWorksheet] = useState(false) + const [editTimesWorksheet, setEditTimesWorksheet] = useState(null) const [showHistoryModal, setShowHistoryModal] = useState(false) const [showProjectsModal, setShowProjectsModal] = useState(false) const [projectsRefreshKey, setProjectsRefreshKey] = useState(0) - const { worksheets, loading: worksheetsLoading, createWorksheet, getTotalTime } = useWorksheets( + const { worksheets, loading: worksheetsLoading, createWorksheet, updateWorksheetTimes, getTotalTime } = useWorksheets( expanded ? ticket.woid : null ) @@ -140,7 +144,13 @@ export default function TicketCard({ ticket, onUpdate }) { )} - + )} @@ -160,6 +170,13 @@ export default function TicketCard({ ticket, onUpdate }) { )} setShowCreateWorksheet(false)} workorder={ticket} onCreate={handleCreateWorksheet} /> + {editTimesWorksheet && ( + setEditTimesWorksheet(null)} + onSave={(ws, times) => updateWorksheetTimes(ws, times, user)} + /> + )} setShowHistoryModal(false)} worksheets={worksheets} ticket={ticket} /> setShowProjectsModal(false)} ticket={ticket} onUpdated={() => setProjectsRefreshKey((k) => k + 1)} /> diff --git a/src/components/WorksheetList.jsx b/src/components/WorksheetList.jsx index 552cbb0..4b71687 100644 --- a/src/components/WorksheetList.jsx +++ b/src/components/WorksheetList.jsx @@ -1,12 +1,22 @@ import { useState } from 'react' -import { FaClock, FaUser, FaExchangeAlt, FaComment, FaChevronDown, FaChevronUp } from 'react-icons/fa' -import { serviceTypeLabel } from '../lib/ticketForm' +import { FaClock, FaUser, FaExchangeAlt, FaComment, FaChevronDown, FaChevronUp, FaPen } from 'react-icons/fa' +import { serviceTypeLabel, canEditWorksheetTimes } from '../lib/ticketForm' function needsTimeEntry(ws) { return ws.serviceType === 'GIT' && (!ws.startTime || !Number(ws.totalTime)) } -export default function WorksheetList({ worksheets, totalTime, loading, onEditTime, onTogglePlan }) { +const headerButtonStyle = { + background: 'rgba(255,255,255,0.25)', + color: 'white', + border: '1px solid rgba(255,255,255,0.4)', + borderRadius: '6px', + padding: '2px 10px', + fontSize: '0.8rem', + marginRight: '8px', +} + +export default function WorksheetList({ worksheets, totalTime, loading, onEditTime, onTogglePlan, currentUser, onEditTimes }) { const [expandedWorksheets, setExpandedWorksheets] = useState({}) if (loading) { return ( @@ -157,14 +167,7 @@ export default function WorksheetList({ worksheets, totalTime, loading, onEditTi )} + {onEditTimes && canEditWorksheetTimes(ws, currentUser) && ( + + )} {onTogglePlan && !ws.isComment && Number(ws.totalTime) > 0 && ( + + + + + ) +} diff --git a/src/hooks/useWorksheets.js b/src/hooks/useWorksheets.js index 38c200f..ec81baa 100644 --- a/src/hooks/useWorksheets.js +++ b/src/hooks/useWorksheets.js @@ -1,5 +1,6 @@ import { useState, useEffect, useCallback } from 'react' import { databases, DATABASE_ID, COLLECTIONS, Query, ID, isDemoMode } from '../lib/appwrite' +import { canEditWorksheetTimes } from '../lib/ticketForm' const DEMO_MODE = isDemoMode @@ -388,6 +389,17 @@ export function useWorksheets(woid = null) { } } + /** + * Aendert nachtraeglich Beginn, Ende und Arbeitszeit - nur fuer den Ersteller + */ + const updateWorksheetTimes = async (worksheet, times, currentUser) => { + if (!canEditWorksheetTimes(worksheet, currentUser)) { + return { success: false, error: 'Nur wer das Arbeitsblatt erstellt hat, kann die Zeiten ändern.' } + } + const { startDate, startTime, endDate, endTime, totalTime } = times + return updateWorksheet(worksheet.$id, { startDate, startTime, endDate, endTime, totalTime }) + } + /** * Löscht ein Worksheet (sollte normalerweise nicht erlaubt sein - Audit Trail!) */ @@ -468,6 +480,7 @@ export function useWorksheets(woid = null) { error, createWorksheet, updateWorksheet, + updateWorksheetTimes, deleteWorksheet, refresh: fetchWorksheets, getTotalTime, diff --git a/src/lib/ticketForm.js b/src/lib/ticketForm.js index e025158..52ac57e 100644 --- a/src/lib/ticketForm.js +++ b/src/lib/ticketForm.js @@ -3,6 +3,8 @@ (siehe planboard.js). Die Kalender-Felder des Browsers liefern dagegen "yyyy-mm-dd" bzw. "hh:mm" - umgerechnet wird erst beim Speichern. */ +import { parseGermanDate, formatTime, dayKey } from './planboard' + // Service Type: gespeichert werden die bisherigen Werte, angezeigt wird Deutsch export const SERVICE_TYPES = [ { value: 'Remote', label: 'Fernwartung (remote)' }, @@ -21,6 +23,12 @@ export function serviceTypeLabel(value) { return SERVICE_TYPE_SHORT[String(value || '').trim().toLowerCase()] || value } +// Zeiten eines Arbeitsblatts darf nur aendern, wer es angelegt hat. +// Reine Kommentare haben keine Arbeitszeit und bleiben aussen vor. +export function canEditWorksheetTimes(worksheet, user) { + return Boolean(user?.$id) && worksheet?.employeeId === user.$id && !worksheet.isComment +} + const pad = (n) => String(n).padStart(2, '0') // Heutiges Datum in Ortszeit als "yyyy-mm-dd" (Wert fuer ) @@ -40,6 +48,17 @@ export function timeToWoms(value) { return m ? `${m[1].padStart(2, '0')}${m[2]}` : '' } +// Rueckweg fuers Bearbeiten: "26.09.2026" (auch "2.5.2026") -> "2026-09-26", sonst "" +export function germanDateToIso(value) { + const date = parseGermanDate(value) + return date ? dayKey(date) : '' +} + +// "0930" -> "09:30", sonst "" +export function womsTimeToInput(value) { + return formatTime(value) +} + // Minuten von "hh:mm" bis "hh:mm"; liegt das Ende davor, geht es ueber Mitternacht export function minutesBetween(start, end) { const a = /^(\d{1,2}):(\d{2})/.exec(String(start || ''))