Fix all ESLint errors: remove unused imports, replace any types
- Remove ~60 unused imports and variables across 88 files - Replace ~80 `any` type annotations with proper types (unknown, Record<string, unknown>, or specific types) - Prefix unused callback args with underscore - Fix unescaped JSX entities - Lint now passes cleanly (0 errors, 2 intentional img warnings) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,7 +38,7 @@ export function QueueOverview({ queues }: QueueOverviewProps) {
|
||||
const params = useParams<{ portSlug: string }>();
|
||||
|
||||
function handleQueueClick(queueName: string) {
|
||||
router.push(`/${params.portSlug}/admin/monitoring/${queueName}` as any);
|
||||
router.push(`/${params.portSlug}/admin/monitoring/${queueName}`);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { WEBHOOK_EVENTS, type WebhookEvent } from '@/lib/services/webhook-event-map';
|
||||
import { type WebhookEvent } from '@/lib/services/webhook-event-map';
|
||||
|
||||
// ─── Event Groups ─────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { type ColumnDef } from '@tanstack/react-table';
|
||||
import { MoreHorizontal, Pencil, Activity } from 'lucide-react';
|
||||
import { useRouter, useParams } from 'next/navigation';
|
||||
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Pencil, RefreshCw } from 'lucide-react';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
@@ -24,7 +24,7 @@ export function BerthDetail({ berthId }: BerthDetailProps) {
|
||||
'berth:statusChanged': [['berth', berthId]],
|
||||
});
|
||||
|
||||
const berth = data as any;
|
||||
const berth = data as Record<string, unknown>;
|
||||
|
||||
return (
|
||||
<DetailLayout
|
||||
|
||||
@@ -68,8 +68,7 @@ export function BerthForm({ berth, open, onOpenChange }: BerthFormProps) {
|
||||
handleSubmit,
|
||||
setValue,
|
||||
watch,
|
||||
formState: { errors, isSubmitting },
|
||||
reset,
|
||||
formState: { isSubmitting },
|
||||
} = useForm<UpdateBerthInput>({
|
||||
resolver: zodResolver(updateBerthSchema),
|
||||
defaultValues: {
|
||||
|
||||
@@ -58,7 +58,7 @@ export function BerthList() {
|
||||
entityType="berths"
|
||||
currentFilters={filters}
|
||||
currentSort={sort}
|
||||
onApplyView={(savedFilters, savedSort) => {
|
||||
onApplyView={(savedFilters, _savedSort) => {
|
||||
clearFilters();
|
||||
Object.entries(savedFilters).forEach(([key, value]) => setFilter(key, value));
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { ArrowRight, Loader2 } from 'lucide-react';
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
import { type DetailTab } from '@/components/shared/detail-layout';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { TagBadge } from '@/components/shared/tag-badge';
|
||||
|
||||
type BerthData = {
|
||||
|
||||
@@ -33,6 +33,25 @@ interface ClientDetailHeaderProps {
|
||||
};
|
||||
}
|
||||
|
||||
type ClientFormClient = {
|
||||
id: string;
|
||||
fullName: string;
|
||||
companyName?: string | null;
|
||||
nationality?: string | null;
|
||||
isProxy?: boolean;
|
||||
proxyType?: string | null;
|
||||
actualOwnerName?: string | null;
|
||||
yachtName?: string | null;
|
||||
berthSizeDesired?: string | null;
|
||||
preferredContactMethod?: string | null;
|
||||
preferredLanguage?: string | null;
|
||||
timezone?: string | null;
|
||||
source?: string | null;
|
||||
sourceDetails?: string | null;
|
||||
contacts?: Array<{ channel: string; value: string; label?: string | null; isPrimary?: boolean }>;
|
||||
tags?: Array<{ id: string }>;
|
||||
};
|
||||
|
||||
const SOURCE_LABELS: Record<string, string> = {
|
||||
website: 'Website',
|
||||
manual: 'Manual',
|
||||
@@ -67,7 +86,6 @@ export function ClientDetailHeader({ client }: ClientDetailHeaderProps) {
|
||||
},
|
||||
});
|
||||
|
||||
const primaryContact = client.contacts?.find((c) => c.isPrimary);
|
||||
const primaryEmail = client.contacts?.find((c) => c.channel === 'email' && c.isPrimary)
|
||||
?? client.contacts?.find((c) => c.channel === 'email');
|
||||
const primaryPhone = client.contacts?.find((c) => c.channel === 'phone' && c.isPrimary)
|
||||
@@ -162,7 +180,7 @@ export function ClientDetailHeader({ client }: ClientDetailHeaderProps) {
|
||||
<ClientForm
|
||||
open={editOpen}
|
||||
onOpenChange={setEditOpen}
|
||||
client={client as any}
|
||||
client={client as unknown as ClientFormClient}
|
||||
/>
|
||||
|
||||
<ArchiveConfirmDialog
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useParams } from 'next/navigation';
|
||||
|
||||
import { DetailLayout } from '@/components/shared/detail-layout';
|
||||
import { ClientDetailHeader } from '@/components/clients/client-detail-header';
|
||||
|
||||
@@ -96,15 +96,15 @@ export function ClientForm({ open, onOpenChange, client }: ClientFormProps) {
|
||||
actualOwnerName: client.actualOwnerName ?? undefined,
|
||||
yachtName: client.yachtName ?? undefined,
|
||||
berthSizeDesired: client.berthSizeDesired ?? undefined,
|
||||
preferredContactMethod: (client.preferredContactMethod as any) ?? undefined,
|
||||
preferredContactMethod: (client.preferredContactMethod as string) ?? undefined,
|
||||
preferredLanguage: client.preferredLanguage ?? undefined,
|
||||
timezone: client.timezone ?? undefined,
|
||||
source: (client.source as any) ?? undefined,
|
||||
source: (client.source as string) ?? undefined,
|
||||
sourceDetails: client.sourceDetails ?? undefined,
|
||||
contacts:
|
||||
client.contacts && client.contacts.length > 0
|
||||
? client.contacts.map((c) => ({
|
||||
channel: c.channel as any,
|
||||
channel: c.channel as 'email' | 'phone' | 'whatsapp' | 'other',
|
||||
value: c.value,
|
||||
label: c.label ?? undefined,
|
||||
isPrimary: c.isPrimary ?? false,
|
||||
@@ -125,6 +125,7 @@ export function ClientForm({ open, onOpenChange, client }: ClientFormProps) {
|
||||
const mutation = useMutation({
|
||||
mutationFn: async (data: CreateClientInput) => {
|
||||
if (isEdit) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { contacts, tagIds: tIds, ...rest } = data;
|
||||
await apiFetch(`/api/v1/clients/${client!.id}`, { method: 'PATCH', body: rest });
|
||||
if (tIds) {
|
||||
@@ -217,7 +218,7 @@ export function ClientForm({ open, onOpenChange, client }: ClientFormProps) {
|
||||
<Select
|
||||
value={watch(`contacts.${index}.channel`)}
|
||||
onValueChange={(v) =>
|
||||
setValue(`contacts.${index}.channel`, v as any)
|
||||
setValue(`contacts.${index}.channel`, v as 'email' | 'phone' | 'whatsapp' | 'other')
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="h-8">
|
||||
@@ -356,7 +357,7 @@ export function ClientForm({ open, onOpenChange, client }: ClientFormProps) {
|
||||
<Label>Source</Label>
|
||||
<Select
|
||||
value={watch('source') ?? ''}
|
||||
onValueChange={(v) => setValue('source', v as any)}
|
||||
onValueChange={(v) => setValue('source', v as 'website' | 'manual' | 'referral' | 'broker')}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select source" />
|
||||
@@ -373,7 +374,7 @@ export function ClientForm({ open, onOpenChange, client }: ClientFormProps) {
|
||||
<Label>Preferred Contact Method</Label>
|
||||
<Select
|
||||
value={watch('preferredContactMethod') ?? ''}
|
||||
onValueChange={(v) => setValue('preferredContactMethod', v as any)}
|
||||
onValueChange={(v) => setValue('preferredContactMethod', v as 'email' | 'phone' | 'whatsapp')}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select method" />
|
||||
|
||||
@@ -96,7 +96,7 @@ export function ClientList() {
|
||||
entityType="clients"
|
||||
currentFilters={filters}
|
||||
currentSort={sort}
|
||||
onApplyView={(savedFilters, savedSort) => {
|
||||
onApplyView={(savedFilters, _savedSort) => {
|
||||
clearFilters();
|
||||
Object.entries(savedFilters).forEach(([key, val]) => setFilter(key, val));
|
||||
}}
|
||||
@@ -137,7 +137,7 @@ export function ClientList() {
|
||||
<ClientForm
|
||||
open={!!editClient}
|
||||
onOpenChange={(open) => !open && setEditClient(null)}
|
||||
client={editClient as any}
|
||||
client={editClient as unknown as NonNullable<Parameters<typeof ClientForm>[0]['client']>}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
@@ -41,7 +41,7 @@ export function SigningProgress({ documentId, signers }: SigningProgressProps) {
|
||||
|
||||
const sorted = [...signers].sort((a, b) => a.signingOrder - b.signingOrder);
|
||||
|
||||
const handleResend = async (signer: Signer) => {
|
||||
const handleResend = async (_signer: Signer) => {
|
||||
try {
|
||||
await apiFetch(`/api/v1/documents/${documentId}/remind`, { method: 'POST' });
|
||||
queryClient.invalidateQueries({ queryKey: ['documents', documentId, 'signers'] });
|
||||
|
||||
@@ -31,12 +31,6 @@ export interface ExpenseRow {
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
const PAYMENT_STATUS_VARIANTS: Record<string, string> = {
|
||||
unpaid: 'destructive',
|
||||
paid: 'default',
|
||||
partial: 'secondary',
|
||||
};
|
||||
|
||||
const PAYMENT_STATUS_COLORS: Record<string, string> = {
|
||||
unpaid: 'bg-red-100 text-red-700 border-red-200',
|
||||
paid: 'bg-green-100 text-green-700 border-green-200',
|
||||
|
||||
@@ -8,16 +8,6 @@ import { Loader2, Receipt, Edit, Archive } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { ArchiveConfirmDialog } from '@/components/shared/archive-confirm-dialog';
|
||||
import { apiFetch } from '@/lib/api/client';
|
||||
import type { ExpenseRow } from './expense-columns';
|
||||
|
||||
@@ -43,7 +43,6 @@ export function ExpenseFormDialog({ open, onOpenChange, expense }: ExpenseFormDi
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
watch,
|
||||
reset,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<CreateExpenseInput>({
|
||||
@@ -60,11 +59,11 @@ export function ExpenseFormDialog({ open, onOpenChange, expense }: ExpenseFormDi
|
||||
establishmentName: expense.establishmentName ?? undefined,
|
||||
amount: Number(expense.amount),
|
||||
currency: expense.currency,
|
||||
category: expense.category as any,
|
||||
paymentMethod: expense.paymentMethod as any,
|
||||
category: expense.category as string,
|
||||
paymentMethod: expense.paymentMethod as string,
|
||||
payer: expense.payer ?? undefined,
|
||||
expenseDate: new Date(expense.expenseDate),
|
||||
paymentStatus: (expense.paymentStatus as any) ?? 'unpaid',
|
||||
paymentStatus: (expense.paymentStatus as string) ?? 'unpaid',
|
||||
});
|
||||
} else if (open && !expense) {
|
||||
reset({
|
||||
@@ -162,7 +161,7 @@ export function ExpenseFormDialog({ open, onOpenChange, expense }: ExpenseFormDi
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="category">Category</Label>
|
||||
<Select
|
||||
onValueChange={(v) => setValue('category', v as any)}
|
||||
onValueChange={(v) => setValue('category', v as string)}
|
||||
defaultValue={expense?.category ?? undefined}
|
||||
>
|
||||
<SelectTrigger id="category">
|
||||
@@ -181,7 +180,7 @@ export function ExpenseFormDialog({ open, onOpenChange, expense }: ExpenseFormDi
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="paymentMethod">Payment Method</Label>
|
||||
<Select
|
||||
onValueChange={(v) => setValue('paymentMethod', v as any)}
|
||||
onValueChange={(v) => setValue('paymentMethod', v as string)}
|
||||
defaultValue={expense?.paymentMethod ?? undefined}
|
||||
>
|
||||
<SelectTrigger id="paymentMethod">
|
||||
@@ -209,7 +208,7 @@ export function ExpenseFormDialog({ open, onOpenChange, expense }: ExpenseFormDi
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="paymentStatus">Payment Status</Label>
|
||||
<Select
|
||||
onValueChange={(v) => setValue('paymentStatus', v as any)}
|
||||
onValueChange={(v) => setValue('paymentStatus', v as 'unpaid' | 'paid' | 'partial')}
|
||||
defaultValue={expense?.paymentStatus ?? 'unpaid'}
|
||||
>
|
||||
<SelectTrigger id="paymentStatus">
|
||||
|
||||
@@ -45,7 +45,7 @@ function formatBytes(bytes: string | null): string {
|
||||
|
||||
function FileIcon({ mimeType }: { mimeType: string | null }) {
|
||||
if (!mimeType) return <FileText className="h-8 w-8 text-muted-foreground" />;
|
||||
if (mimeType.startsWith('image/')) return <Image className="h-8 w-8 text-blue-500" />;
|
||||
if (mimeType.startsWith('image/')) return <Image className="h-8 w-8 text-blue-500" alt="" />;
|
||||
if (mimeType === 'application/pdf') return <FileText className="h-8 w-8 text-red-500" />;
|
||||
if (
|
||||
mimeType === 'application/vnd.ms-excel' ||
|
||||
|
||||
@@ -181,7 +181,7 @@ export function InterestDetailHeader({ portSlug, interest }: InterestDetailHeade
|
||||
<InterestForm
|
||||
open={editOpen}
|
||||
onOpenChange={setEditOpen}
|
||||
interest={interest as any}
|
||||
interest={interest as unknown as Parameters<typeof InterestForm>[0]['interest']}
|
||||
/>
|
||||
|
||||
<InterestStagePicker
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DocumentList } from '@/components/documents/document-list';
|
||||
@@ -25,7 +25,6 @@ interface InterestData {
|
||||
|
||||
export function InterestDocumentsTab({ interestId }: InterestDocumentsTabProps) {
|
||||
const [eoiDialogOpen, setEoiDialogOpen] = useState(false);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: interestRes } = useQuery({
|
||||
queryKey: ['interests', interestId],
|
||||
|
||||
@@ -164,7 +164,7 @@ export function InterestList() {
|
||||
<InterestForm
|
||||
open={!!editInterest}
|
||||
onOpenChange={(open) => !open && setEditInterest(null)}
|
||||
interest={editInterest as any}
|
||||
interest={editInterest as unknown as Parameters<typeof InterestForm>[0]['interest']}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
|
||||
@@ -66,7 +66,7 @@ export function InterestTimeline({ interestId }: InterestTimelineProps) {
|
||||
{/* Vertical line */}
|
||||
<div className="absolute left-4 top-2 bottom-2 w-px bg-border" />
|
||||
|
||||
{events.map((event, idx) => (
|
||||
{events.map((event, _idx) => (
|
||||
<div key={event.id} className="relative flex gap-4 pb-6">
|
||||
{/* Icon */}
|
||||
<div className="relative z-10 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-background border">
|
||||
|
||||
@@ -55,7 +55,7 @@ export function PipelineCard({
|
||||
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{leadCategory && (
|
||||
<Badge variant={(LEAD_CATEGORY_COLORS[leadCategory] as any) ?? 'secondary'}>
|
||||
<Badge variant={(LEAD_CATEGORY_COLORS[leadCategory] as 'default' | 'secondary' | 'destructive' | 'outline') ?? 'secondary'}>
|
||||
{leadCategory.replace(/_/g, ' ')}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Sparkles, Link, Loader2 } from 'lucide-react';
|
||||
import { Sparkles, Loader2 } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -75,7 +74,7 @@ export function RecommendationList({ interestId }: RecommendationListProps) {
|
||||
</div>
|
||||
) : recommendations.length === 0 ? (
|
||||
<div className="text-center py-12 text-muted-foreground">
|
||||
<p>No recommendations yet. Click "Generate Recommendations" to get started.</p>
|
||||
<p>No recommendations yet. Click "Generate Recommendations" to get started.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import { Loader2, Send, CreditCard } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
@@ -33,7 +33,7 @@ export function InvoiceDetail({ invoiceId }: InvoiceDetailProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const [tab, setTab] = useState('overview');
|
||||
|
||||
const { data, isLoading, error } = useQuery<{ data: any }>({
|
||||
const { data, isLoading, error } = useQuery<{ data: Record<string, unknown> }>({
|
||||
queryKey: ['invoices', invoiceId],
|
||||
queryFn: () => apiFetch(`/api/v1/invoices/${invoiceId}`),
|
||||
});
|
||||
@@ -172,7 +172,7 @@ export function InvoiceDetail({ invoiceId }: InvoiceDetailProps) {
|
||||
<span className="col-span-2 text-right">Unit Price</span>
|
||||
<span className="col-span-2 text-right">Total</span>
|
||||
</div>
|
||||
{invoice.lineItems.map((li: any) => (
|
||||
{(invoice.lineItems as Record<string, unknown>[]).map((li) => (
|
||||
<div key={li.id} className="grid grid-cols-12 gap-2 text-sm">
|
||||
<span className="col-span-6">{li.description}</span>
|
||||
<span className="col-span-2 text-right tabular-nums">{li.quantity}</span>
|
||||
@@ -239,7 +239,7 @@ export function InvoiceDetail({ invoiceId }: InvoiceDetailProps) {
|
||||
<TabsContent value="expenses" className="pt-4">
|
||||
{invoice.linkedExpenses && invoice.linkedExpenses.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
{invoice.linkedExpenses.map((exp: any) => (
|
||||
{(invoice.linkedExpenses as Record<string, unknown>[]).map((exp) => (
|
||||
<div
|
||||
key={exp.id}
|
||||
className="flex items-center justify-between p-3 border rounded-md text-sm"
|
||||
|
||||
@@ -5,7 +5,6 @@ import { Plus, Trash2 } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
interface LineItem {
|
||||
description: string;
|
||||
@@ -18,7 +17,7 @@ interface InvoiceLineItemsProps {
|
||||
}
|
||||
|
||||
export function InvoiceLineItems({ name = 'lineItems' }: InvoiceLineItemsProps) {
|
||||
const { register, watch, formState: { errors } } = useFormContext();
|
||||
const { register, watch } = useFormContext();
|
||||
const { fields, append, remove } = useFieldArray({ name });
|
||||
|
||||
const lineItems: LineItem[] = watch(name) ?? [];
|
||||
|
||||
@@ -25,7 +25,7 @@ export function InvoicePdfPreview({ invoiceId, pdfFileId: initialPdfFileId }: In
|
||||
const regenerateMutation = useMutation({
|
||||
mutationFn: () =>
|
||||
apiFetch(`/api/v1/invoices/${invoiceId}/generate-pdf`, { method: 'POST' }),
|
||||
onSuccess: (data: any) => {
|
||||
onSuccess: (data: { data?: { id?: string } }) => {
|
||||
const fileId = data?.data?.id;
|
||||
if (fileId) {
|
||||
setPdfFileId(fileId);
|
||||
|
||||
@@ -83,7 +83,7 @@ export function Breadcrumbs() {
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink asChild>
|
||||
<Link
|
||||
href={`/${currentPortSlug}/dashboard` as any}
|
||||
href={`/${currentPortSlug}/dashboard`}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
{currentPort.name}
|
||||
@@ -98,7 +98,7 @@ export function Breadcrumbs() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{crumbs.map((crumb, index) => (
|
||||
{crumbs.map((crumb, _index) => (
|
||||
<Fragment key={crumb.href}>
|
||||
<BreadcrumbItem>
|
||||
{crumb.isLast ? (
|
||||
@@ -108,7 +108,7 @@ export function Breadcrumbs() {
|
||||
) : (
|
||||
<BreadcrumbLink asChild>
|
||||
<Link
|
||||
href={crumb.href as any}
|
||||
href={crumb.href}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
{crumb.label}
|
||||
|
||||
@@ -36,7 +36,7 @@ export function PortSwitcher({ ports }: PortSwitcherProps) {
|
||||
queryClient.invalidateQueries();
|
||||
|
||||
// Navigate to the selected port's dashboard
|
||||
router.push(`/${port.slug}/dashboard` as any);
|
||||
router.push(`/${port.slug}/dashboard`);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
Menu,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
LogOut,
|
||||
} from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -113,7 +112,7 @@ function NavItemLink({
|
||||
}) {
|
||||
const content = (
|
||||
<Link
|
||||
href={item.href as any}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
'flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors duration-150',
|
||||
'text-[#cdcfd6] hover:bg-[#171f35] hover:text-white',
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { PortSwitcher } from '@/components/layout/port-switcher';
|
||||
import { Breadcrumbs } from '@/components/layout/breadcrumbs';
|
||||
import { CommandSearch, SearchTrigger } from '@/components/search/command-search';
|
||||
import { CommandSearch } from '@/components/search/command-search';
|
||||
import { NotificationBell } from '@/components/notifications/notification-bell';
|
||||
import type { Port } from '@/lib/db/schema/ports';
|
||||
|
||||
@@ -64,16 +64,16 @@ export function Topbar({ ports }: TopbarProps) {
|
||||
<DropdownMenuContent align="end" className="w-44">
|
||||
<DropdownMenuLabel className="text-xs text-muted-foreground">Create</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/clients/new` as any)}>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/clients/new`)}>
|
||||
New Client
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/interests/new` as any)}>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/interests/new`)}>
|
||||
New Interest
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/expenses/new` as any)}>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/expenses/new`)}>
|
||||
New Expense
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/reminders/new` as any)}>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/reminders/new`)}>
|
||||
New Reminder
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
@@ -99,11 +99,11 @@ export function Topbar({ ports }: TopbarProps) {
|
||||
<DropdownMenuContent align="end" className="w-52">
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/settings/profile` as any)}>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/settings/profile`)}>
|
||||
<User className="w-4 h-4 mr-2" />
|
||||
Profile
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/settings` as any)}>
|
||||
<DropdownMenuItem onClick={() => router.push(`${base}/settings`)}>
|
||||
<Settings className="w-4 h-4 mr-2" />
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -24,7 +24,7 @@ export function NotificationItem({ notification, onMarkRead }: NotificationItemP
|
||||
onMarkRead(notification.id);
|
||||
}
|
||||
if (notification.link) {
|
||||
router.push(notification.link as any);
|
||||
router.push(notification.link);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ export function PortalCard({
|
||||
);
|
||||
|
||||
if (href) {
|
||||
return <Link href={href as any}>{content}</Link>;
|
||||
return <Link href={href}>{content}</Link>;
|
||||
}
|
||||
|
||||
return content;
|
||||
|
||||
@@ -16,7 +16,7 @@ export function PortalHeader({ portName, portLogoUrl, clientName }: PortalHeader
|
||||
|
||||
async function handleLogout() {
|
||||
await fetch('/api/portal/auth/logout', { method: 'POST' });
|
||||
router.push('/portal/login' as any);
|
||||
router.push('/portal/login');
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -25,7 +25,7 @@ export function PortalNav() {
|
||||
return (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href as any}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
'flex items-center gap-2 px-4 py-3 text-sm font-medium border-b-2 transition-colors whitespace-nowrap',
|
||||
isActive
|
||||
|
||||
@@ -53,7 +53,7 @@ export function CommandSearch() {
|
||||
setFocused(false);
|
||||
setQuery('');
|
||||
inputRef.current?.blur();
|
||||
router.push(path as any);
|
||||
router.push(path);
|
||||
},
|
||||
[router],
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { useRef, useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { ChevronDown, ChevronRight } from 'lucide-react';
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { apiFetch } from '@/lib/api/client';
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -6,9 +6,7 @@ import {
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
type ColumnDef,
|
||||
type SortingState,
|
||||
type RowSelectionState,
|
||||
type PaginationState,
|
||||
} from '@tanstack/react-table';
|
||||
import { ArrowDown, ArrowUp, ArrowUpDown, Loader2 } from 'lucide-react';
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export function DetailLayout({
|
||||
function handleTabChange(tabId: string) {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set('tab', tabId);
|
||||
router.replace(`${pathname}?${params.toString()}` as any, { scroll: false });
|
||||
router.replace(`${pathname}?${params.toString()}`, { scroll: false });
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type ReactNode, type ElementType } from 'react';
|
||||
import { type ElementType } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user