This commit is contained in:
2026-04-06 02:32:47 +03:00
parent 5f3d208158
commit 24a44481a0
152 changed files with 85913 additions and 44338 deletions
@@ -10,15 +10,11 @@ import { useAuthApi } from "@/shared/useApi"
import { confirm } from "@/shared/components/confirm-dialog"
import { Button } from "@/shared/components/ui/button"
import { Card, CardContent } from "@/shared/components/ui/card"
import { JOB_CARD_ROUTES } from "@garage/api"
import { JOB_CARD_ROUTES, JobCardResponseData } from "@garage/api"
import DashboardPage from "@/base/components/layout/dashboard/dashboard-page"
import { useJobCard } from "@/modules/job-cards/job-card-context"
import { CONSTANTS } from "@/config/constants"
type Attachment = {
id: number
file_name: string
url: string
mime_type?: string
created_at?: string
}
function getFileIcon(mimeType?: string) {
if (mimeType?.startsWith("image/")) return ImageIcon
@@ -35,13 +31,9 @@ export default function JobCardAttachmentsPage() {
const queryKey = [JOB_CARD_ROUTES.INDEX, jobCardId, "attachments"]
const { data, isLoading } = useQuery({
queryKey,
queryFn: () => api.jobCards.show(jobCardId),
})
const jobcard = useJobCard()
const jobCard = (data as any)?.data ?? data
const attachments: Attachment[] = jobCard?.documents ?? jobCard?.attachments ?? []
const attachments = jobcard?.attachment_files
const deleteMutation = useMutation({
mutationFn: (attachmentId: number) =>
@@ -55,10 +47,10 @@ export default function JobCardAttachmentsPage() {
},
})
const handleDelete = async (attachment: Attachment) => {
const handleDelete = async (attachment: JobCardResponseData['attachment_files'][number]) => {
const confirmed = await confirm({
title: "Delete Attachment",
description: `Are you sure you want to delete "${attachment.file_name}"?`,
description: `Are you sure you want to delete "${attachment.original_name}"?`,
confirmLabel: "Delete",
variant: "destructive",
})
@@ -91,31 +83,30 @@ export default function JobCardAttachmentsPage() {
}
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-end">
<input
ref={fileInputRef}
type="file"
multiple
className="hidden"
onChange={handleUpload}
/>
<Button
onClick={() => fileInputRef.current?.click()}
disabled={isUploading}
>
<Plus className="size-4" />
{isUploading ? "Uploading..." : "Upload Attachment"}
</Button>
</div>
<DashboardPage
header={null}
toolbar={
<div className="flex items-center justify-end">
<input
ref={fileInputRef}
type="file"
multiple
className="hidden"
onChange={handleUpload}
/>
<Button
onClick={() => fileInputRef.current?.click()}
disabled={isUploading}
>
<Plus className="size-4" />
{isUploading ? "Uploading..." : "Upload Attachment"}
</Button>
</div>}
title="Attachments"
>
{isLoading ? (
<Card>
<CardContent className="py-8 text-center text-muted-foreground">
Loading attachments...
</CardContent>
</Card>
) : attachments.length === 0 ? (
{attachments?.length === 0 ? (
<Card>
<CardContent className="py-8 text-center text-muted-foreground">
No attachments yet. Click "Upload Attachment" to add files.
@@ -123,8 +114,8 @@ export default function JobCardAttachmentsPage() {
</Card>
) : (
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
{attachments.map((attachment) => {
const Icon = getFileIcon(attachment.mime_type)
{attachments?.map((attachment) => {
const Icon = getFileIcon(attachment.attachment_path)
return (
<Card key={attachment.id}>
<CardContent className="flex items-center gap-3 p-4">
@@ -133,13 +124,13 @@ export default function JobCardAttachmentsPage() {
</div>
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
<a
href={attachment.url}
href={CONSTANTS.getAssetUrl(attachment.attachment_path)}
target="_blank"
rel="noopener noreferrer"
className="truncate text-sm font-medium hover:underline"
title={attachment.file_name}
title={attachment.original_name}
>
{attachment.file_name}
{attachment.original_name}
</a>
{attachment.created_at && (
<span className="text-xs text-muted-foreground">
@@ -161,6 +152,6 @@ export default function JobCardAttachmentsPage() {
})}
</div>
)}
</div>
</DashboardPage>
)
}