Compare commits
5
Commits
f6b329b208
...
7a3bc2887e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a3bc2887e | ||
|
|
416c79b3a6 | ||
|
|
e54a30b006 | ||
|
|
a0149137ea | ||
|
|
dd0bef52e8 |
No files matched your search
@@ -0,0 +1,45 @@
|
||||
/* Planboard-Anzeigelogik: reine Texte und Klassen, die PlanboardPage braucht.
|
||||
Die Terminlogik selbst (Datum lesen, nach Tag gruppieren) steckt in planboard.js. */
|
||||
import { format, getISOWeek, addDays } from 'date-fns'
|
||||
import { de } from 'date-fns/locale'
|
||||
|
||||
const NOBODY = 'niemand zugewiesen'
|
||||
|
||||
// "Kalenderwoche 41 · 5. Oktober bis 11. Oktober 2026 · 13 Termine"
|
||||
// weekStart muss ein Montag sein (die Woche läuft bis weekStart + 6 Tage). Das Ende trägt immer das Jahr, der Anfang nur,
|
||||
// wenn sein Jahr vom Ende abweicht: "28. Dezember 2026 bis 3. Januar 2027".
|
||||
export function planboardSubtitle({ weekStart, count = 0, loading = false }) {
|
||||
const weekEnd = addDays(weekStart, 6)
|
||||
const sameYear = weekStart.getFullYear() === weekEnd.getFullYear()
|
||||
const from = format(weekStart, sameYear ? 'd. MMMM' : 'd. MMMM yyyy', { locale: de })
|
||||
const to = format(weekEnd, 'd. MMMM yyyy', { locale: de })
|
||||
const rest = loading ? 'Wird geladen …' : `${count} ${count === 1 ? 'Termin' : 'Termine'}`
|
||||
return `Kalenderwoche ${getISOWeek(weekStart)} · ${from} bis ${to} · ${rest}`
|
||||
}
|
||||
|
||||
export function dayLabels(day) {
|
||||
return {
|
||||
weekday: format(day, 'EEEE', { locale: de }),
|
||||
number: format(day, 'dd.MM'),
|
||||
full: format(day, 'EEEE, d. MMMM yyyy', { locale: de }),
|
||||
}
|
||||
}
|
||||
|
||||
export function appointmentClass(type) {
|
||||
return String(type || '').toLowerCase() === 'akquise' ? 'appt akquise' : 'appt'
|
||||
}
|
||||
|
||||
export function appointmentTimeLabel({ time, endTime }) {
|
||||
if (!time) return 'ohne Uhrzeit'
|
||||
return endTime ? `${time}–${endTime}` : time
|
||||
}
|
||||
|
||||
// Mit Ticketnummer "#100201 · KNSO", ohne Nummer nur der Mitarbeiter (kein leeres "#")
|
||||
export function appointmentOwnerLabel({ woid, employeeName, employeeShort }) {
|
||||
const owner = employeeName ? employeeShort || employeeName : NOBODY
|
||||
return woid ? `#${woid} · ${owner}` : owner
|
||||
}
|
||||
|
||||
export function appointmentTitle({ woid }) {
|
||||
return woid ? `Ticket #${woid} öffnen` : 'Ticket öffnen'
|
||||
}
|
||||
+48
-90
@@ -1,26 +1,19 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { format, addDays, startOfWeek, isSameDay } from 'date-fns'
|
||||
import { de } from 'date-fns/locale'
|
||||
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa6'
|
||||
import { PageHeader, Card, Button } from '../components/ui'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { addDays, startOfWeek, isSameDay } from 'date-fns'
|
||||
import { PageHeader, Button } from '../components/ui'
|
||||
import { useWorkorders } from '../hooks/useWorkorders'
|
||||
import { useEmployees } from '../hooks/useEmployees'
|
||||
import { groupAppointmentsByDay, countInRange, dayKey } from '../lib/planboard'
|
||||
import { ticketPath } from '../lib/ticketRoutes'
|
||||
import { ticketPath, ticketRef } from '../lib/ticketRoutes'
|
||||
import {
|
||||
planboardSubtitle, dayLabels, appointmentClass, appointmentTimeLabel, appointmentOwnerLabel, appointmentTitle,
|
||||
} from '../lib/planboardView'
|
||||
|
||||
/* Termine haengen an den Tickets (startDate/startTime/endTime/assignedTo);
|
||||
die Aufbereitung steckt in src/lib/planboard.js. */
|
||||
|
||||
// Farben nur ueber Tokens (P3 baut die Seite um)
|
||||
const TYPE_COLORS = {
|
||||
akquise: { bg: 'var(--appt-akquise)', fg: 'var(--orange-fg)' },
|
||||
webpage: { bg: 'var(--bg-hover)', fg: 'var(--text-2)' },
|
||||
project: { bg: 'var(--bg-hover)', fg: 'var(--text-2)' },
|
||||
}
|
||||
die Aufbereitung steckt in src/lib/planboard.js, die Texte in src/lib/planboardView.js. */
|
||||
|
||||
export default function PlanboardPage() {
|
||||
const navigate = useNavigate()
|
||||
const [currentWeek, setCurrentWeek] = useState(startOfWeek(new Date(), { weekStartsOn: 1 }))
|
||||
const { workorders, loading } = useWorkorders({ limit: 500 })
|
||||
const { employees } = useEmployees()
|
||||
@@ -36,87 +29,52 @@ export default function PlanboardPage() {
|
||||
<div className="page">
|
||||
<PageHeader
|
||||
title="Planboard"
|
||||
subtitle={loading ? 'Wochenplanung – lädt…' : `Wochenplanung – ${weekCount} ${weekCount === 1 ? 'Termin' : 'Termine'} diese Woche`}
|
||||
subtitle={planboardSubtitle({ weekStart: currentWeek, count: weekCount, loading })}
|
||||
actions={
|
||||
<div className="flex gap-2 items-center">
|
||||
<Button variant="ghost" onClick={() => navigateWeek(-1)}><FaChevronLeft /></Button>
|
||||
<span className="muted" style={{ minWidth: 200, textAlign: 'center' }}>
|
||||
{format(currentWeek, 'dd.MM.yyyy')} - {format(addDays(currentWeek, 6), 'dd.MM.yyyy')}
|
||||
</span>
|
||||
<Button variant="ghost" onClick={() => navigateWeek(1)}><FaChevronRight /></Button>
|
||||
<Button variant="ghost" onClick={goToday}>Heute</Button>
|
||||
</div>
|
||||
<>
|
||||
<Button variant="quiet" aria-label="Vorherige Woche" onClick={() => navigateWeek(-1)}>←</Button>
|
||||
<Button onClick={goToday}>Heute</Button>
|
||||
<Button variant="quiet" aria-label="Nächste Woche" onClick={() => navigateWeek(1)}>→</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="planboard-scroll">
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 12 }}>
|
||||
{weekDays.map((day) => {
|
||||
const entries = byDay[dayKey(day)] || []
|
||||
const today = isSameDay(day, new Date())
|
||||
return (
|
||||
<Card key={day.toISOString()} pad={false}>
|
||||
<div style={{
|
||||
padding: '10px 12px',
|
||||
borderBottom: '1px solid var(--border)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
background: today ? 'var(--appt-akquise)' : undefined,
|
||||
}}>
|
||||
<strong style={{ fontSize: 13 }}>{format(day, 'EEEE', { locale: de })}</strong>
|
||||
<span className="muted" style={{ fontSize: 12 }}>{format(day, 'dd.MM')}</span>
|
||||
</div>
|
||||
<div className="week">
|
||||
{weekDays.map((day, index) => {
|
||||
const entries = byDay[dayKey(day)] || []
|
||||
const today = isSameDay(day, new Date())
|
||||
const labels = dayLabels(day)
|
||||
return (
|
||||
<div
|
||||
key={day.toISOString()}
|
||||
className={`day${today ? ' today' : ''}${index >= 5 ? ' weekend' : ''}`}
|
||||
role="group"
|
||||
aria-label={labels.full}
|
||||
aria-current={today ? 'date' : undefined}
|
||||
>
|
||||
<div className="day-head">
|
||||
<span className="wd">{labels.weekday}</span>
|
||||
<span className="dn">{labels.number}</span>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 8, minHeight: 120, display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
{entries.length === 0 && (
|
||||
<p className="faint" style={{ fontSize: 12, padding: '4px 4px 0' }}>Keine Termine</p>
|
||||
)}
|
||||
{entries.length === 0 && <div className="none">Keine Termine</div>}
|
||||
|
||||
{entries.map((entry) => {
|
||||
const color = TYPE_COLORS[String(entry.type).toLowerCase()]
|
||||
|| { bg: 'var(--bg-subtle)', fg: 'var(--line-strong)' }
|
||||
return (
|
||||
<button
|
||||
key={entry.id}
|
||||
type="button"
|
||||
title={`Ticket #${entry.woid} öffnen`}
|
||||
onClick={() => navigate(ticketPath(entry.woid || entry.id))}
|
||||
style={{
|
||||
textAlign: 'left',
|
||||
border: '1px solid var(--border)',
|
||||
borderLeft: `3px solid ${color.fg}`,
|
||||
borderRadius: 8,
|
||||
background: color.bg,
|
||||
color: 'inherit',
|
||||
padding: '8px 10px',
|
||||
cursor: 'pointer',
|
||||
font: 'inherit',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 12, fontWeight: 700 }}>
|
||||
{entry.time ? `${entry.time}${entry.endTime ? `–${entry.endTime}` : ''}` : 'ohne Uhrzeit'}
|
||||
</span>
|
||||
<span style={{ fontSize: 12.5, fontWeight: 600, lineHeight: 1.25 }}>
|
||||
{entry.customerName || entry.topic}
|
||||
</span>
|
||||
{entry.customerName && (
|
||||
<span className="muted" style={{ fontSize: 11.5, lineHeight: 1.25 }}>{entry.topic}</span>
|
||||
)}
|
||||
<span className="muted" style={{ fontSize: 11 }}>
|
||||
#{entry.woid}
|
||||
{entry.employeeName ? ` · ${entry.employeeShort || entry.employeeName}` : ' · niemand zugewiesen'}
|
||||
</span>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{entries.map((entry) => (
|
||||
<Link
|
||||
key={entry.id}
|
||||
className={appointmentClass(entry.type)}
|
||||
to={ticketPath(ticketRef({ woid: entry.woid, $id: entry.id }))}
|
||||
title={appointmentTitle(entry)}
|
||||
>
|
||||
<div className="tm">{appointmentTimeLabel(entry)}</div>
|
||||
<div className="tt">{entry.customerName || entry.topic}</div>
|
||||
{entry.customerName && <div className="cu">{entry.topic}</div>}
|
||||
<div className="cu">{appointmentOwnerLabel(entry)}</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
+35
-4
@@ -557,9 +557,6 @@ a.list-row:hover .cell-title { color: var(--accent-ink); }
|
||||
.wrap { flex-wrap: wrap; }
|
||||
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
|
||||
.text-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
/* Planboard (bis P3): die 7-Spalten-Woche scrollt waagerecht im Container, nicht die Seite */
|
||||
.planboard-scroll { overflow-x: auto; }
|
||||
|
||||
/* Neues Ticket: Datum + Uhrzeit nebeneinander (heller Kalender, kein color-scheme: dark) */
|
||||
.datetime-pair { display: flex; gap: 8px; }
|
||||
.datetime-pair .form-control, .datetime-pair .input { flex: 1; min-width: 0; }
|
||||
@@ -1012,6 +1009,40 @@ button.link { font-weight: 500; } /* font: inherit setzt sonst das Gewicht von .
|
||||
}
|
||||
/* ===== ENDE Tickets (P2) ===== */
|
||||
|
||||
/* ===== Planboard (P3) ===== */
|
||||
/* Woche ohne Karten: sieben Tagesspalten mit feinen Trennlinien, Wochenende hell abgesetzt, heute als schwarze Datumspille */
|
||||
.week { display: grid; grid-template-columns: repeat(7, minmax(128px, 1fr)); border-top: 1px solid var(--line); min-height: 420px; overflow-x: auto; }
|
||||
.day { border-left: 1px solid var(--line); padding: 10px 8px 16px; min-width: 0; }
|
||||
.day:first-child { border-left: 0; padding-left: 0; }
|
||||
.day-head { display: flex; align-items: baseline; gap: 6px; margin-bottom: 12px; padding-left: 4px; flex-wrap: wrap; row-gap: 0; }
|
||||
.day-head .wd { font-size: 12px; color: var(--text-2); font-weight: 500; text-transform: uppercase; letter-spacing: 0.04em; }
|
||||
.day-head .dn { font-size: 18px; font-weight: 600; font-variant-numeric: tabular-nums; }
|
||||
.day.today .wd { color: var(--text); }
|
||||
.day.today .dn { background: var(--accent); color: #fff; border-radius: 99px; padding: 0 8px; }
|
||||
.day.weekend { background: var(--bg-subtle); }
|
||||
.appt { display: block; padding: 8px 10px; border-radius: var(--radius); background: var(--bg-hover); margin-bottom: 6px; font-size: 13px; line-height: 18px; overflow-wrap: anywhere; }
|
||||
.appt:hover { background: var(--appt-hover); }
|
||||
.appt .tm { font-weight: 600; font-variant-numeric: tabular-nums; }
|
||||
.appt .tt { color: var(--text); margin-top: 2px; }
|
||||
.appt .cu { color: var(--text-2); margin-top: 2px; }
|
||||
.appt.akquise { background: var(--appt-akquise); }
|
||||
.appt.akquise:hover { background: var(--appt-akquise-hover); }
|
||||
.appt:focus-visible { outline-offset: -2px; } /* im Scroll-Container .week wuerde der Ring sonst abgeschnitten */
|
||||
.day.weekend .appt:not(.akquise) { background: var(--bg); }
|
||||
.day.weekend .appt:not(.akquise):hover { background: var(--appt-hover); }
|
||||
.day .none { font-size: 12px; color: var(--text-2); padding-left: 4px; }
|
||||
/* Ab 861 px stehen die Spalten nebeneinander: Wochentag ueber der Datumszahl, in jeder Spalte gleich hoch, alle Termine beginnen auf einer Hoehe */
|
||||
@media (min-width: 861px) {
|
||||
.day-head { flex-direction: column; align-items: flex-start; gap: 0; }
|
||||
}
|
||||
@media (max-width: 860px) {
|
||||
.week { grid-template-columns: 1fr; border-top: 0; min-height: 0; overflow-x: visible; }
|
||||
.day { border-left: 0; padding: 12px 0; border-top: 1px solid var(--line); }
|
||||
.day.weekend { background: none; }
|
||||
.day.weekend .appt:not(.akquise) { background: var(--bg-hover); }
|
||||
}
|
||||
/* ===== ENDE Planboard (P3) ===== */
|
||||
|
||||
/* ===== KOMPAT (bis P10) ===== */
|
||||
/* Uebergangsschicht: alte Klassen im neuen Look, damit Seiten und Dialoge, die noch nicht umgebaut sind, weiss, kastenlos */
|
||||
/* und lesbar bleiben. Steht am Dateiende und gewinnt dort gegen die Altregeln und gegen die anderen Stylesheets (global.css */
|
||||
@@ -1122,7 +1153,7 @@ div.row { display: flex; flex-wrap: wrap; margin: 0 -8px; }
|
||||
.fin-link:hover, .legal-files a:hover, .credit-cols a:hover, .area-rows a:hover { text-decoration-color: currentColor; }
|
||||
|
||||
/* Abschnitte (Card = <section>) als Spalten nebeneinander: der Abstand .page section + section gilt nur fuer untereinander stehende Abschnitte */
|
||||
.planboard-scroll section + section, .legal-grid > section + section, .fin-cols > section + section,
|
||||
.legal-grid > section + section, .fin-cols > section + section,
|
||||
.page div[style*="display: grid"] > section + section { margin-top: 0; }
|
||||
|
||||
/* Altformulare mit <Field> (Kunde, Projekt zuweisen, Neuer Lead): Zeilenabstand wie frueher; neue Container bestimmen ihren Abstand selbst */
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { loadModule } from './load.mjs'
|
||||
|
||||
const { parseGermanDate, formatTime, dayKey, groupAppointmentsByDay, countInRange } = await loadModule('src/lib/planboard.js')
|
||||
|
||||
test('parseGermanDate: ein- und zweistellig, Altwerte ergeben null', () => {
|
||||
assert.equal(parseGermanDate('2.5.2026').getTime(), new Date(2026, 4, 2).getTime())
|
||||
assert.equal(parseGermanDate(' 07.10.2026 ').getTime(), new Date(2026, 9, 7).getTime())
|
||||
for (const v of ['31.02.2026', '0.1.2026', '2026-10-07T09:00:00.000Z', '2026-10-07', '7.10.26', '', undefined, null, 'morgen']) {
|
||||
assert.equal(parseGermanDate(v), null, String(v))
|
||||
}
|
||||
})
|
||||
|
||||
test('formatTime: hhmm und hh:mm, ungültige Werte ergeben leer', () => {
|
||||
for (const [v, out] of [['0900', '09:00'], ['900', '09:00'], ['9:00', '09:00'], ['09:30', '09:30'], ['2359', '23:59']]) {
|
||||
assert.equal(formatTime(v), out, v)
|
||||
}
|
||||
for (const v of ['2400', '1260', '9', 'abc', '', undefined]) assert.equal(formatTime(v), '', String(v))
|
||||
assert.equal(dayKey(new Date(2026, 0, 5)), '2026-01-05')
|
||||
})
|
||||
|
||||
const employees = [{ userId: 'u1', displayName: 'Kenso Grimm', shortcode: 'KNSO' }]
|
||||
const workorders = [
|
||||
{ $id: 'a', woid: '1', startDate: '7.10.2026', startTime: '1400', endTime: '1500', topic: 'Spät', type: 'Webpage', status: 'Open', customerName: 'Alpha', assignedTo: 'u1' },
|
||||
{ $id: 'b', woid: '2', startDate: '07.10.2026', startTime: '', topic: 'Ohne Uhrzeit', type: 'Akquise', status: 'Open', assignedName: 'Ehemalige' },
|
||||
{ $id: 'c', woid: '3', startDate: '7.10.2026', startTime: '0830', topic: 'Früh', type: 'Webpage', status: 'Cancelled' },
|
||||
{ $id: 'd', startDate: '8.10.2026', startTime: '1000', title: 'Nur Titel' },
|
||||
{ $id: 'h', startDate: '9.10.2026' },
|
||||
{ $id: 'e', woid: '5', startDate: '31.02.2026', startTime: '1000', topic: 'Ungültig' },
|
||||
{ $id: 'f', woid: '6', startDate: '2026-10-07T09:00:00.000Z', topic: 'ISO' },
|
||||
{ $id: 'g', woid: '7', startDate: '', topic: 'Leer' },
|
||||
]
|
||||
|
||||
test('groupAppointmentsByDay: nach Uhrzeit, ohne Uhrzeit am Ende, Stornierte bleiben, Altwerte fallen weg', () => {
|
||||
const byDay = groupAppointmentsByDay(workorders, employees)
|
||||
assert.deepEqual(Object.keys(byDay).sort(), ['2026-10-07', '2026-10-08', '2026-10-09'])
|
||||
assert.deepEqual(byDay['2026-10-07'].map((a) => a.id), ['c', 'a', 'b'])
|
||||
assert.equal(byDay['2026-10-07'][0].status, 'Cancelled')
|
||||
assert.equal(byDay['2026-10-07'][1].employeeShort, 'KNSO')
|
||||
assert.equal(byDay['2026-10-07'][1].employeeName, 'Kenso Grimm')
|
||||
assert.equal(byDay['2026-10-07'][2].employeeName, 'Ehemalige')
|
||||
assert.equal(byDay['2026-10-07'][2].employeeShort, '')
|
||||
assert.equal(byDay['2026-10-08'][0].woid, '')
|
||||
assert.equal(byDay['2026-10-08'][0].topic, 'Nur Titel')
|
||||
assert.equal(byDay['2026-10-09'][0].topic, 'Ohne Betreff')
|
||||
})
|
||||
|
||||
test('countInRange: zählt nur die genannten Tage', () => {
|
||||
const byDay = groupAppointmentsByDay(workorders, employees)
|
||||
const week = (day) => Array.from({ length: 7 }, (_, i) => new Date(2026, 9, day + i))
|
||||
assert.equal(countInRange(byDay, week(5)), 5)
|
||||
assert.equal(countInRange(byDay, week(12)), 0)
|
||||
assert.equal(countInRange(byDay), 0)
|
||||
})
|
||||
@@ -0,0 +1,43 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { loadModule } from './load.mjs'
|
||||
|
||||
const { planboardSubtitle, dayLabels, appointmentClass, appointmentTimeLabel, appointmentOwnerLabel, appointmentTitle } =
|
||||
await loadModule('src/lib/planboardView.js')
|
||||
|
||||
test('planboardSubtitle: Kalenderwoche, Zeitraum, Terminzahl', () => {
|
||||
const mo = new Date(2026, 9, 5)
|
||||
assert.equal(planboardSubtitle({ weekStart: mo, count: 13 }), 'Kalenderwoche 41 · 5. Oktober bis 11. Oktober 2026 · 13 Termine')
|
||||
assert.equal(planboardSubtitle({ weekStart: mo, count: 1 }), 'Kalenderwoche 41 · 5. Oktober bis 11. Oktober 2026 · 1 Termin')
|
||||
assert.equal(planboardSubtitle({ weekStart: mo, count: 0 }), 'Kalenderwoche 41 · 5. Oktober bis 11. Oktober 2026 · 0 Termine')
|
||||
assert.equal(planboardSubtitle({ weekStart: mo, count: 0, loading: true }), 'Kalenderwoche 41 · 5. Oktober bis 11. Oktober 2026 · Wird geladen …')
|
||||
assert.equal(planboardSubtitle({ weekStart: new Date(2026, 11, 28), count: 2 }), 'Kalenderwoche 53 · 28. Dezember 2026 bis 3. Januar 2027 · 2 Termine')
|
||||
assert.equal(planboardSubtitle({ weekStart: new Date(2027, 0, 4), count: 2 }), 'Kalenderwoche 1 · 4. Januar bis 10. Januar 2027 · 2 Termine')
|
||||
})
|
||||
|
||||
test('dayLabels: Wochentag, Datum, volles Datum', () => {
|
||||
assert.deepEqual(dayLabels(new Date(2026, 9, 5)), { weekday: 'Montag', number: '05.10', full: 'Montag, 5. Oktober 2026' })
|
||||
assert.deepEqual(dayLabels(new Date(2026, 9, 11)), { weekday: 'Sonntag', number: '11.10', full: 'Sonntag, 11. Oktober 2026' })
|
||||
})
|
||||
|
||||
test('appointmentClass und appointmentTimeLabel', () => {
|
||||
for (const t of ['Akquise', 'akquise', 'AKQUISE']) assert.equal(appointmentClass(t), 'appt akquise', t)
|
||||
for (const t of ['Webpage', 'Project', 'Migration', '', undefined, null]) assert.equal(appointmentClass(t), 'appt', String(t))
|
||||
assert.equal(appointmentTimeLabel({ time: '08:00', endTime: '09:30' }), '08:00–09:30')
|
||||
assert.equal(appointmentTimeLabel({ time: '08:00', endTime: '' }), '08:00')
|
||||
assert.equal(appointmentTimeLabel({ time: '', endTime: '09:30' }), 'ohne Uhrzeit')
|
||||
assert.equal(appointmentTimeLabel({ time: '', endTime: '' }), 'ohne Uhrzeit')
|
||||
})
|
||||
|
||||
test('appointmentOwnerLabel: Nummer und Mitarbeiter', () => {
|
||||
assert.equal(appointmentOwnerLabel({ woid: '100201', employeeName: 'Kenso Grimm', employeeShort: 'KNSO' }), '#100201 · KNSO')
|
||||
assert.equal(appointmentOwnerLabel({ woid: '100201', employeeName: 'Ehemalige', employeeShort: '' }), '#100201 · Ehemalige')
|
||||
assert.equal(appointmentOwnerLabel({ woid: '100201', employeeName: '', employeeShort: '' }), '#100201 · niemand zugewiesen')
|
||||
assert.equal(appointmentOwnerLabel({ woid: '', employeeName: 'Kenso Grimm', employeeShort: 'KNSO' }), 'KNSO')
|
||||
assert.equal(appointmentOwnerLabel({ woid: '', employeeName: '', employeeShort: '' }), 'niemand zugewiesen')
|
||||
})
|
||||
|
||||
test('appointmentTitle: Tooltip mit und ohne woid', () => {
|
||||
assert.equal(appointmentTitle({ woid: '100201' }), 'Ticket #100201 öffnen')
|
||||
assert.equal(appointmentTitle({ woid: '' }), 'Ticket öffnen')
|
||||
})
|
||||
Reference in new issue
Block a user