fix: resolve all ruff and ESLint lint errors
Backend (ruff): - F821: Add TYPE_CHECKING imports for Vehicle, Contact, File in models (file.py, retouch.py, sale.py, vehicle.py) - E741: Rename ambiguous variable to / (copilot_service.py, price_compare_service.py, openrouter.py) - F841: Remove unused variable in sale_service.py Frontend (ESLint): - react/no-unescaped-entities: Escape quotes in ContractPreview.tsx - @next/next/no-img-element: Replace <img> with <Image> from next/image (FileGallery.tsx, FileList.tsx, FilePreview.tsx, BeforeAfterSlider.tsx) Tests: 392 backend passed, 112 frontend passed, next build successful
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, func
|
from sqlalchemy import DateTime, ForeignKey, Integer, String, func
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
@@ -9,6 +10,9 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|||||||
|
|
||||||
from app.database import Base
|
from app.database import Base
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from app.models.vehicle import Vehicle
|
||||||
|
|
||||||
|
|
||||||
class File(Base):
|
class File(Base):
|
||||||
"""File attachment entity linked to a vehicle."""
|
"""File attachment entity linked to a vehicle."""
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import enum
|
import enum
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import DateTime, ForeignKey, String, Text, func
|
from sqlalchemy import DateTime, ForeignKey, String, Text, func
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
@@ -10,6 +11,9 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|||||||
|
|
||||||
from app.database import Base
|
from app.database import Base
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from app.models.vehicle import Vehicle
|
||||||
|
|
||||||
|
|
||||||
class RetouchStatus(str, enum.Enum):
|
class RetouchStatus(str, enum.Enum):
|
||||||
pending = "pending"
|
pending = "pending"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import enum
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Boolean,
|
Boolean,
|
||||||
@@ -20,6 +21,10 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|||||||
|
|
||||||
from app.database import Base
|
from app.database import Base
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from app.models.contact import Contact
|
||||||
|
from app.models.vehicle import Vehicle
|
||||||
|
|
||||||
|
|
||||||
class SaleStatus(str, enum.Enum):
|
class SaleStatus(str, enum.Enum):
|
||||||
draft = "draft"
|
draft = "draft"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import enum
|
import enum
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import Boolean, DateTime, Enum, String, func
|
from sqlalchemy import Boolean, DateTime, Enum, String, func
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import enum
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
CheckConstraint,
|
CheckConstraint,
|
||||||
Date,
|
Date,
|
||||||
DateTime,
|
DateTime,
|
||||||
Enum,
|
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
Integer,
|
Integer,
|
||||||
Numeric,
|
Numeric,
|
||||||
@@ -22,6 +22,9 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|||||||
|
|
||||||
from app.database import Base
|
from app.database import Base
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from app.models.file import File
|
||||||
|
|
||||||
|
|
||||||
class VehicleCondition(str, enum.Enum):
|
class VehicleCondition(str, enum.Enum):
|
||||||
new = "new"
|
new = "new"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from fastapi.responses import Response
|
from fastapi.responses import Response
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_db
|
||||||
from app.dependencies import get_current_user, get_pagination, require_role
|
from app.dependencies import get_pagination, require_role
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.schemas.user import (
|
from app.schemas.user import (
|
||||||
UserCreate,
|
UserCreate,
|
||||||
@@ -17,7 +17,6 @@ from app.schemas.user import (
|
|||||||
from app.services.auth_service import (
|
from app.services.auth_service import (
|
||||||
create_user as svc_create_user,
|
create_user as svc_create_user,
|
||||||
deactivate_user as svc_deactivate_user,
|
deactivate_user as svc_deactivate_user,
|
||||||
get_user_by_id,
|
|
||||||
list_users as svc_list_users,
|
list_users as svc_list_users,
|
||||||
update_user as svc_update_user,
|
update_user as svc_update_user,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||||||
from app.database import get_db
|
from app.database import get_db
|
||||||
from app.dependencies import get_current_user, get_pagination
|
from app.dependencies import get_current_user, get_pagination
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.models.vehicle import Vehicle
|
|
||||||
from app.schemas.vehicle import (
|
from app.schemas.vehicle import (
|
||||||
MobileDePushResponse,
|
MobileDePushResponse,
|
||||||
MobileDeStatusResponse,
|
MobileDeStatusResponse,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Literal, Optional
|
from typing import Literal, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||||
|
|
||||||
from app.utils.ust_validation import validate_vat_id
|
from app.utils.ust_validation import validate_vat_id
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from datetime import date, datetime
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Literal, Optional
|
from typing import Literal, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||||
|
|
||||||
|
|
||||||
VEHICLE_TYPES = Literal["lkw", "pkw", "baumaschine", "stapler", "transporter"]
|
VEHICLE_TYPES = Literal["lkw", "pkw", "baumaschine", "stapler", "transporter"]
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ def _parse_ai_response(raw_content: str) -> dict[str, Any]:
|
|||||||
# Strip markdown code fences if present
|
# Strip markdown code fences if present
|
||||||
if text.startswith("```"):
|
if text.startswith("```"):
|
||||||
lines = text.split("\n")
|
lines = text.split("\n")
|
||||||
lines = [l for l in lines if not l.strip().startswith("```")]
|
lines = [line for line in lines if not line.strip().startswith("```")]
|
||||||
text = "\n".join(lines).strip()
|
text = "\n".join(lines).strip()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import os
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from sqlalchemy import and_, func, select
|
from sqlalchemy import and_, func, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
@@ -14,7 +13,7 @@ from sqlalchemy.orm import selectinload
|
|||||||
|
|
||||||
from app.models.datev_export import DATEVExport
|
from app.models.datev_export import DATEVExport
|
||||||
from app.models.sale import Sale
|
from app.models.sale import Sale
|
||||||
from app.utils.datev import generate_datev_csv, validate_datev_csv
|
from app.utils.datev import generate_datev_csv
|
||||||
|
|
||||||
|
|
||||||
async def create_export(
|
async def create_export(
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ Enforces MAX_FILE_SIZE_MB from config (default 50MB, but endpoint enforces 20MB)
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
import uuid
|
import uuid
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from sqlalchemy import and_, select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from sqlalchemy import and_, func, select
|
from sqlalchemy import and_, func, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
@@ -83,7 +82,7 @@ async def compare_prices(
|
|||||||
|
|
||||||
# Calculate average price
|
# Calculate average price
|
||||||
if listings:
|
if listings:
|
||||||
average_price = round(sum(l.price for l in listings) / len(listings), 2)
|
average_price = round(sum(listing.price for listing in listings) / len(listings), 2)
|
||||||
else:
|
else:
|
||||||
average_price = None
|
average_price = None
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import date, datetime, timezone
|
from datetime import date
|
||||||
from decimal import Decimal
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import and_, func, select
|
from sqlalchemy import and_, func, select
|
||||||
@@ -26,7 +25,6 @@ async def create_sale(db: AsyncSession, data: dict[str, Any]) -> Sale:
|
|||||||
Raises ValueError if vehicle or buyer contact not found.
|
Raises ValueError if vehicle or buyer contact not found.
|
||||||
"""
|
"""
|
||||||
vehicle_id = data["vehicle_id"]
|
vehicle_id = data["vehicle_id"]
|
||||||
buyer_contact_id = data["buyer_contact_id"]
|
|
||||||
|
|
||||||
# Verify vehicle exists
|
# Verify vehicle exists
|
||||||
vehicle = await db.get(Vehicle, vehicle_id)
|
vehicle = await db.get(Vehicle, vehicle_id)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from typing import Any
|
|||||||
|
|
||||||
from sqlalchemy import and_, func, or_, select
|
from sqlalchemy import and_, func, or_, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import selectinload
|
|
||||||
|
|
||||||
from app.models.vehicle import Vehicle
|
from app.models.vehicle import Vehicle
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
|
|
||||||
from app.database import async_session_factory
|
from app.database import async_session_factory
|
||||||
from app.services.ocr_service import process_ocr
|
from app.services.ocr_service import process_ocr
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ from datetime import date
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from app.config import settings
|
|
||||||
|
|
||||||
|
|
||||||
# HTML template for the sales contract
|
# HTML template for the sales contract
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ Datum, Konto, Gegenkonto, Betrag, Belegfeld, Buchungstext
|
|||||||
|
|
||||||
import csv
|
import csv
|
||||||
import io
|
import io
|
||||||
from datetime import date
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ def _parse_response(raw_content: str) -> dict[str, Any]:
|
|||||||
if text.startswith("```"):
|
if text.startswith("```"):
|
||||||
lines = text.split("\n")
|
lines = text.split("\n")
|
||||||
# Remove first line (```json or ```) and last line (```)
|
# Remove first line (```json or ```) and last line (```)
|
||||||
lines = [l for l in lines if not l.strip().startswith("```")]
|
lines = [line for line in lines if not line.strip().startswith("```")]
|
||||||
text = "\n".join(lines).strip()
|
text = "\n".join(lines).strip()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"extends":"next/core-web-vitals"}
|
||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
getThumbnailUrl,
|
getThumbnailUrl,
|
||||||
type FileResponse,
|
type FileResponse,
|
||||||
} from '@/lib/files';
|
} from '@/lib/files';
|
||||||
|
import Image from 'next/image';
|
||||||
import { FilePreview } from './FilePreview';
|
import { FilePreview } from './FilePreview';
|
||||||
|
|
||||||
interface FileGalleryProps {
|
interface FileGalleryProps {
|
||||||
@@ -76,10 +77,12 @@ export function FileGallery({ vehicleId }: FileGalleryProps) {
|
|||||||
data-testid={`gallery-item-${image.id}`}
|
data-testid={`gallery-item-${image.id}`}
|
||||||
>
|
>
|
||||||
{thumbUrl && (
|
{thumbUrl && (
|
||||||
<img
|
<Image
|
||||||
src={thumbUrl}
|
src={thumbUrl}
|
||||||
alt={image.original_filename}
|
alt={image.original_filename}
|
||||||
className="w-full h-full object-cover transition-transform group-hover:scale-105"
|
fill
|
||||||
|
className="object-cover transition-transform group-hover:scale-105"
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/30 transition-colors flex items-end p-2">
|
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/30 transition-colors flex items-end p-2">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Modal } from '@/components/ui/Modal';
|
import { Modal } from '@/components/ui/Modal';
|
||||||
import {
|
import {
|
||||||
@@ -124,13 +125,15 @@ export function FileList({ vehicleId, onFileDeleted }: FileListProps) {
|
|||||||
data-testid={`file-item-${file.id}`}
|
data-testid={`file-item-${file.id}`}
|
||||||
>
|
>
|
||||||
{/* Thumbnail or file icon */}
|
{/* Thumbnail or file icon */}
|
||||||
<div className="aspect-square bg-background flex items-center justify-center">
|
<div className="aspect-square bg-background flex items-center justify-center relative">
|
||||||
{isImg && thumbUrl ? (
|
{isImg && thumbUrl ? (
|
||||||
<img
|
<Image
|
||||||
src={thumbUrl}
|
src={thumbUrl}
|
||||||
alt={file.original_filename}
|
alt={file.original_filename}
|
||||||
className="w-full h-full object-cover"
|
fill
|
||||||
|
className="object-cover"
|
||||||
data-testid={`file-thumb-${file.id}`}
|
data-testid={`file-thumb-${file.id}`}
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center gap-2 text-text-muted">
|
<div className="flex flex-col items-center gap-2 text-text-muted">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import Image from 'next/image';
|
||||||
import { Modal } from '@/components/ui/Modal';
|
import { Modal } from '@/components/ui/Modal';
|
||||||
import { isImageMime, formatFileSize, type FileResponse } from '@/lib/files';
|
import { isImageMime, formatFileSize, type FileResponse } from '@/lib/files';
|
||||||
|
|
||||||
@@ -22,11 +23,14 @@ export function FilePreview({ file, open, onClose }: FilePreviewProps) {
|
|||||||
{/* Preview content */}
|
{/* Preview content */}
|
||||||
{isImg ? (
|
{isImg ? (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<img
|
<Image
|
||||||
src={downloadUrl}
|
src={downloadUrl}
|
||||||
alt={file.original_filename}
|
alt={file.original_filename}
|
||||||
|
width={800}
|
||||||
|
height={600}
|
||||||
className="max-w-full max-h-[60vh] rounded-lg"
|
className="max-w-full max-h-[60vh] rounded-lg"
|
||||||
data-testid="preview-image"
|
data-testid="preview-image"
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useCallback, useRef, useEffect } from 'react';
|
import { useState, useCallback, useRef, useEffect } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
interface BeforeAfterSliderProps {
|
interface BeforeAfterSliderProps {
|
||||||
beforeSrc: string;
|
beforeSrc: string;
|
||||||
@@ -78,12 +79,14 @@ export function BeforeAfterSlider({
|
|||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
{/* After image (full, background) */}
|
{/* After image (full, background) */}
|
||||||
<img
|
<Image
|
||||||
src={afterSrc}
|
src={afterSrc}
|
||||||
alt={afterLabel}
|
alt={afterLabel}
|
||||||
className="absolute inset-0 w-full h-full object-cover"
|
fill
|
||||||
|
className="object-cover"
|
||||||
data-testid="after-image"
|
data-testid="after-image"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Before image (clipped to left of slider) */}
|
{/* Before image (clipped to left of slider) */}
|
||||||
@@ -91,13 +94,15 @@ export function BeforeAfterSlider({
|
|||||||
className="absolute inset-0 overflow-hidden"
|
className="absolute inset-0 overflow-hidden"
|
||||||
style={{ width: `${sliderPos}%` }}
|
style={{ width: `${sliderPos}%` }}
|
||||||
>
|
>
|
||||||
<img
|
<Image
|
||||||
src={beforeSrc}
|
src={beforeSrc}
|
||||||
alt={beforeLabel}
|
alt={beforeLabel}
|
||||||
className="absolute inset-0 h-full object-cover"
|
fill
|
||||||
|
className="object-cover"
|
||||||
style={{ width: `${containerRef.current?.clientWidth || 100}%` }}
|
style={{ width: `${containerRef.current?.clientWidth || 100}%` }}
|
||||||
data-testid="before-image"
|
data-testid="before-image"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function ContractPreview({ saleId, contractPdfPath }: ContractPreviewProp
|
|||||||
<div className="bg-gray-50 p-8 text-center rounded" data-testid="contract-empty">
|
<div className="bg-gray-50 p-8 text-center rounded" data-testid="contract-empty">
|
||||||
<p className="text-gray-500">Es wurde noch kein Vertrag generiert.</p>
|
<p className="text-gray-500">Es wurde noch kein Vertrag generiert.</p>
|
||||||
<p className="text-sm text-gray-400 mt-2">
|
<p className="text-sm text-gray-400 mt-2">
|
||||||
Klicken Sie auf "Vertrag neu generieren", um ein PDF zu erstellen.
|
Klicken Sie auf "Vertrag neu generieren", um ein PDF zu erstellen.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Generated
+4011
-1
File diff suppressed because it is too large
Load Diff
+11
-9
@@ -12,22 +12,24 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "14.2.5",
|
"next": "14.2.5",
|
||||||
|
"next-intl": "3.17.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1"
|
||||||
"next-intl": "3.17.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "5.5.4",
|
"@testing-library/jest-dom": "6.4.8",
|
||||||
|
"@testing-library/react": "16.0.1",
|
||||||
"@types/node": "20.14.0",
|
"@types/node": "20.14.0",
|
||||||
"@types/react": "18.3.3",
|
"@types/react": "18.3.3",
|
||||||
"@types/react-dom": "18.3.0",
|
"@types/react-dom": "18.3.0",
|
||||||
"tailwindcss": "3.4.7",
|
"@vitejs/plugin-react": "4.3.1",
|
||||||
"postcss": "8.4.40",
|
|
||||||
"autoprefixer": "10.4.19",
|
"autoprefixer": "10.4.19",
|
||||||
"vitest": "2.0.5",
|
"eslint": "^8.57.1",
|
||||||
"@testing-library/react": "16.0.1",
|
"eslint-config-next": "^14.2.35",
|
||||||
"@testing-library/jest-dom": "6.4.8",
|
|
||||||
"jsdom": "24.1.1",
|
"jsdom": "24.1.1",
|
||||||
"@vitejs/plugin-react": "4.3.1"
|
"postcss": "8.4.40",
|
||||||
|
"tailwindcss": "3.4.7",
|
||||||
|
"typescript": "5.5.4",
|
||||||
|
"vitest": "2.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user