241 lines
5.9 KiB
TypeScript
241 lines
5.9 KiB
TypeScript
import { cn } from '@/lib/utils'
|
|
import { createFileRoute } from '@tanstack/react-router'
|
|
import { format } from 'date-fns'
|
|
import {
|
|
BotIcon,
|
|
CircleUserIcon,
|
|
ClipboardCheckIcon,
|
|
ProjectorIcon,
|
|
ReceiptEuroIcon,
|
|
SpeakerIcon,
|
|
} from 'lucide-react'
|
|
import { ReactNode } from 'react'
|
|
import { string } from 'zod'
|
|
|
|
export const Route = createFileRoute('/_sidebar/projects/view/$id/audit')({
|
|
component: RouteComponent,
|
|
beforeLoad: () => {
|
|
return {
|
|
breadcrumb: 'Audit',
|
|
}
|
|
},
|
|
})
|
|
|
|
enum TimelineAction {
|
|
General,
|
|
Equipment,
|
|
Personal,
|
|
Finance,
|
|
Todo,
|
|
}
|
|
|
|
enum TimelineActionType {
|
|
Good,
|
|
Bad,
|
|
Neutral,
|
|
}
|
|
|
|
type TimelineEntry = {
|
|
title: string
|
|
description: string
|
|
date: Date
|
|
action: TimelineAction
|
|
actionType: TimelineActionType
|
|
}
|
|
|
|
const timelineEntries: Array<TimelineEntry> = [
|
|
{
|
|
title: 'Payed #5',
|
|
description: 'Client payed bill number 5.',
|
|
action: TimelineAction.Finance,
|
|
date: new Date(2025, 12, 5, 10, 54, 23),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'Confirmed #1',
|
|
description: 'Client confirmed project 1.',
|
|
action: TimelineAction.General,
|
|
date: new Date(2025, 12, 4, 11),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'New Task',
|
|
description: 'Konstantin Hintermayer added task 1.',
|
|
action: TimelineAction.Todo,
|
|
date: new Date(),
|
|
actionType: TimelineActionType.Neutral,
|
|
},
|
|
{
|
|
title: 'Payed #5',
|
|
description: 'Client payed bill number 5.',
|
|
action: TimelineAction.Finance,
|
|
date: new Date(2025, 12, 5, 10, 54, 23),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'Confirmed #1',
|
|
description: 'Client confirmed project 1.',
|
|
action: TimelineAction.General,
|
|
date: new Date(2025, 12, 4, 11),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'New Task',
|
|
description: 'Konstantin Hintermayer added task 1.',
|
|
action: TimelineAction.Todo,
|
|
date: new Date(),
|
|
actionType: TimelineActionType.Neutral,
|
|
},
|
|
{
|
|
title: 'Payed #5',
|
|
description: 'Client payed bill number 5.',
|
|
action: TimelineAction.Finance,
|
|
date: new Date(2025, 12, 5, 10, 54, 23),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'Confirmed #1',
|
|
description: 'Client confirmed project 1.',
|
|
action: TimelineAction.General,
|
|
date: new Date(2025, 12, 4, 11),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'New Task',
|
|
description: 'Konstantin Hintermayer added task 1.',
|
|
action: TimelineAction.Todo,
|
|
date: new Date(),
|
|
actionType: TimelineActionType.Neutral,
|
|
},
|
|
{
|
|
title: 'Payed #5',
|
|
description: 'Client payed bill number 5.',
|
|
action: TimelineAction.Finance,
|
|
date: new Date(2025, 12, 5, 10, 54, 23),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'Confirmed #1',
|
|
description: 'Client confirmed project 1.',
|
|
action: TimelineAction.General,
|
|
date: new Date(2025, 12, 4, 11),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'New Task',
|
|
description: 'Konstantin Hintermayer added task 1.',
|
|
action: TimelineAction.Todo,
|
|
date: new Date(),
|
|
actionType: TimelineActionType.Neutral,
|
|
},
|
|
{
|
|
title: 'Payed #5',
|
|
description: 'Client payed bill number 5.',
|
|
action: TimelineAction.Finance,
|
|
date: new Date(2025, 12, 5, 10, 54, 23),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'Confirmed #1',
|
|
description: 'Client confirmed project 1.',
|
|
action: TimelineAction.General,
|
|
date: new Date(2025, 12, 4, 11),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'New Task',
|
|
description: 'Konstantin Hintermayer added task 1.',
|
|
action: TimelineAction.Todo,
|
|
date: new Date(),
|
|
actionType: TimelineActionType.Neutral,
|
|
},
|
|
{
|
|
title: 'Payed #5',
|
|
description: 'Client payed bill number 5.',
|
|
action: TimelineAction.Finance,
|
|
date: new Date(2025, 12, 5, 10, 54, 23),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'Confirmed #1',
|
|
description: 'Client confirmed project 1.',
|
|
action: TimelineAction.General,
|
|
date: new Date(2025, 12, 4, 11),
|
|
actionType: TimelineActionType.Good,
|
|
},
|
|
{
|
|
title: 'New Task',
|
|
description: 'Konstantin Hintermayer added task 1.',
|
|
action: TimelineAction.Todo,
|
|
date: new Date(),
|
|
actionType: TimelineActionType.Neutral,
|
|
},
|
|
]
|
|
|
|
function GetIconFromAction(ta: TimelineAction) {
|
|
switch (ta) {
|
|
case TimelineAction.Equipment:
|
|
return <SpeakerIcon className="h-6" />
|
|
case TimelineAction.Finance:
|
|
return <ReceiptEuroIcon className="h-6" />
|
|
case TimelineAction.General:
|
|
return <BotIcon className="h-6" />
|
|
case TimelineAction.Personal:
|
|
return <CircleUserIcon className="h-6" />
|
|
case TimelineAction.Todo:
|
|
return <ClipboardCheckIcon className="h-6" />
|
|
default:
|
|
return <p>Icon not found</p>
|
|
}
|
|
}
|
|
|
|
function GetColorFromActionType(at: TimelineActionType) {
|
|
switch (at) {
|
|
case TimelineActionType.Bad:
|
|
return 'bg-red-500'
|
|
case TimelineActionType.Good:
|
|
return 'bg-green-500'
|
|
case TimelineActionType.Neutral:
|
|
return 'bg-muted'
|
|
}
|
|
}
|
|
|
|
function Timeline({ children }: { children: ReactNode }) {
|
|
return (
|
|
<div className="relative">
|
|
{children}
|
|
<div className="h-full absolute top-0 left-timeline-line w-[2px] bg-muted"></div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function TimelineEntryComponent({ te }: { te: TimelineEntry }) {
|
|
return (
|
|
<div className="flex m-2 gap-3">
|
|
<div
|
|
className={cn(
|
|
`h-8 aspect-square flex items-center justify-center rounded-full border-2 border-background z-10`,
|
|
GetColorFromActionType(te.actionType),
|
|
)}
|
|
>
|
|
{GetIconFromAction(te.action)}
|
|
</div>
|
|
<div>
|
|
{format(te.date, 'hh:mm dd.MM.yyyy')} {te.title}
|
|
<br />
|
|
{te.description}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function RouteComponent() {
|
|
return (
|
|
<Timeline>
|
|
{timelineEntries.map((te, i) => {
|
|
return <TimelineEntryComponent te={te} key={i}></TimelineEntryComponent>
|
|
})}
|
|
</Timeline>
|
|
)
|
|
}
|