diff --git a/resources/js/components/app-mobile-nav.tsx b/resources/js/components/app-mobile-nav.tsx deleted file mode 100644 index bb8693ee..00000000 --- a/resources/js/components/app-mobile-nav.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function AppMobileNav() { - return null; -} diff --git a/resources/js/components/appearance-dropdown.tsx b/resources/js/components/appearance-dropdown.tsx deleted file mode 100644 index 15375fa3..00000000 --- a/resources/js/components/appearance-dropdown.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Button } from '@/components/ui/button'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { useAppearance } from '@/hooks/use-appearance'; -import { __ } from '@/utils/i18n'; -import { Monitor, Moon, Sun } from 'lucide-react'; -import { HTMLAttributes } from 'react'; - -export default function AppearanceToggleDropdown({ - className = '', - ...props -}: HTMLAttributes) { - const { appearance, updateAppearance } = useAppearance(); - - const getCurrentIcon = () => { - switch (appearance) { - case 'dark': - return ; - case 'light': - return ; - default: - return ; - } - }; - - return ( -
- - - - - - updateAppearance('light')}> - - - {__('Light')} - - - updateAppearance('dark')}> - - - {__('Dark')} - - - updateAppearance('system')} - > - - - {__('System')} - - - - -
- ); -} diff --git a/resources/js/components/dashboard/stat-card.tsx b/resources/js/components/dashboard/stat-card.tsx deleted file mode 100644 index 65e110a4..00000000 --- a/resources/js/components/dashboard/stat-card.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { cn } from '@/lib/utils'; -import { ArrowDownIcon, ArrowUpIcon, LucideIcon } from 'lucide-react'; - -interface StatCardProps { - title: string; - value: string; - description?: string; - icon?: LucideIcon; - trend?: { - value: number; - label: string; - }; - className?: string; - loading?: boolean; -} - -export function StatCard({ - title, - value, - description, - icon: Icon, - trend, - className, - loading, -}: StatCardProps) { - if (loading) { - return ( - - - - {title} - - {Icon && } - - -
-
- - - ); - } - - return ( - - - {title} - {Icon && } - - -
{value}
- {(description || trend) && ( -
- {trend && ( - 0 - ? 'text-green-600' - : trend.value < 0 - ? 'text-red-600' - : '', - )} - > - {trend.value > 0 ? ( - - ) : trend.value < 0 ? ( - - ) : null} - {Math.abs(trend.value).toFixed(1)}% - - )} - {trend?.label || description} -
- )} -
-
- ); -} diff --git a/resources/js/components/landing/encryption-video-player.tsx b/resources/js/components/landing/encryption-video-player.tsx deleted file mode 100644 index 79ce2c06..00000000 --- a/resources/js/components/landing/encryption-video-player.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { cn } from '@/lib/utils'; -import { RotateCcwIcon } from 'lucide-react'; -import { useCallback, useEffect, useRef, useState } from 'react'; - -interface EncryptionVideoPlayerProps { - lightSrc: string; - darkSrc: string; - className?: string; -} - -export default function EncryptionVideoPlayer({ - lightSrc, - darkSrc, - className, -}: EncryptionVideoPlayerProps) { - const lightVideoRef = useRef(null); - const darkVideoRef = useRef(null); - const containerRef = useRef(null); - const [hasEnded, setHasEnded] = useState(false); - const [isHovering, setIsHovering] = useState(false); - const hasPlayedRef = useRef(false); - - const handleReplay = useCallback(() => { - const lightVideo = lightVideoRef.current; - const darkVideo = darkVideoRef.current; - - if (lightVideo) { - lightVideo.currentTime = 0; - lightVideo.play().catch(() => { - // Autoplay was prevented - user will need to interact - }); - } - if (darkVideo) { - darkVideo.currentTime = 0; - darkVideo.play().catch(() => { - // Autoplay was prevented - user will need to interact - }); - } - setHasEnded(false); - }, []); - - const handleEnded = useCallback(() => { - setHasEnded(true); - }, []); - - useEffect(() => { - const container = containerRef.current; - const lightVideo = lightVideoRef.current; - const darkVideo = darkVideoRef.current; - - if (!container || !lightVideo || !darkVideo) return; - - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting && !hasPlayedRef.current) { - hasPlayedRef.current = true; - lightVideo.play().catch(() => { - // Autoplay was prevented - user will need to interact - }); - darkVideo.play().catch(() => { - // Autoplay was prevented - user will need to interact - }); - } - }); - }, - { - threshold: 0.5, - }, - ); - - observer.observe(container); - - return () => { - observer.disconnect(); - }; - }, []); - - return ( -
setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} - > -
-
- - {/* Replay button - visible on hover when video has ended */} - {hasEnded && ( - - )} -
- ); -} diff --git a/resources/js/components/sync-status-button.tsx b/resources/js/components/sync-status-button.tsx deleted file mode 100644 index 2c851698..00000000 --- a/resources/js/components/sync-status-button.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { Button } from '@/components/ui/button'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { useSyncContext } from '@/contexts/sync-context'; -import { __ } from '@/utils/i18n'; -import { formatDistanceToNow } from 'date-fns'; -import { CloudAlert, CloudCheck, CloudOff, RefreshCw } from 'lucide-react'; -import { useState } from 'react'; - -export function SyncStatusButton() { - const { syncStatus, lastSyncTime, isOnline, sync, error } = - useSyncContext(); - const [isMenuOpen, setIsMenuOpen] = useState(false); - - const getIcon = () => { - if (syncStatus === 'syncing') { - return ; - } - - if (syncStatus === 'error') { - return ; - } - - if (!isOnline) { - return ; - } - - return ; - }; - - const getLastSyncText = () => { - if (lastSyncTime) { - return `Synced ${formatDistanceToNow(lastSyncTime, { addSuffix: true })}`; - } - return 'Not synced yet'; - }; - - const getStatusText = () => { - if (syncStatus === 'syncing') { - return 'Syncing...'; - } - if (!isOnline) { - return 'Offline'; - } - if (syncStatus === 'error') { - return error || 'Sync failed'; - } - return getLastSyncText(); - }; - - const handleSyncNow = () => { - sync(); - }; - - return ( - - - - - - -

{getStatusText()}

-
- - { - e.preventDefault(); - handleSyncNow(); - }} - disabled={syncStatus === 'syncing' || !isOnline} - > - - {__('Sync now')} - -
-
- ); -} diff --git a/resources/js/components/transactions/date-header.tsx b/resources/js/components/transactions/date-header.tsx deleted file mode 100644 index b2f33c71..00000000 --- a/resources/js/components/transactions/date-header.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { format, getYear, parseISO } from 'date-fns'; - -export interface DateHeaderProps { - date: string; - colSpan: number; -} - -export function DateHeader({ date, colSpan }: DateHeaderProps) { - const parsedDate = parseISO(date); - const currentYear = getYear(new Date()); - const transactionYear = getYear(parsedDate); - const formatString = - transactionYear === currentYear ? 'MMM d' : 'MMM d, yy'; - - return ( - - - {format(parsedDate, formatString)} - - - ); -} diff --git a/resources/js/components/transactions/transaction-list.tsx b/resources/js/components/transactions/transaction-list.tsx index d30445d5..796e47e2 100644 --- a/resources/js/components/transactions/transaction-list.tsx +++ b/resources/js/components/transactions/transaction-list.tsx @@ -862,7 +862,7 @@ export function TransactionList({ consoleDebug('=== Re-evaluation complete ==='); } }, - [categories, accounts, banks, updateTransaction, automationRules], + [updateTransaction], ); async function handleBulkReEvaluateRules() { diff --git a/resources/js/components/ui/amount-input.tsx b/resources/js/components/ui/amount-input.tsx index 5b036015..bde95c63 100644 --- a/resources/js/components/ui/amount-input.tsx +++ b/resources/js/components/ui/amount-input.tsx @@ -179,7 +179,7 @@ export const AmountInput = React.forwardRef( setDisplayValue(formatCurrency(value, locale)); } } - }, [value, isFocused]); + }, [value, isFocused, locale]); const handleFocus = () => { setIsFocused(true); diff --git a/resources/js/components/ui/avatar.tsx b/resources/js/components/ui/avatar.tsx index b7224f00..1e1516d3 100644 --- a/resources/js/components/ui/avatar.tsx +++ b/resources/js/components/ui/avatar.tsx @@ -1,51 +1,51 @@ -import * as React from "react" -import * as AvatarPrimitive from "@radix-ui/react-avatar" +import * as AvatarPrimitive from '@radix-ui/react-avatar'; +import * as React from 'react'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; function Avatar({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ) + return ( + + ); } function AvatarImage({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ) + return ( + + ); } function AvatarFallback({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ) + return ( + + ); } -export { Avatar, AvatarImage, AvatarFallback } +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/resources/js/components/ui/glowing-effect.tsx b/resources/js/components/ui/glowing-effect.tsx index 25c4c416..6a6a5fa4 100644 --- a/resources/js/components/ui/glowing-effect.tsx +++ b/resources/js/components/ui/glowing-effect.tsx @@ -77,7 +77,7 @@ const GlowingEffect = memo( const currentAngle = parseFloat(element.style.getPropertyValue("--start")) || 0; - let targetAngle = + const targetAngle = (180 * Math.atan2(mouseY - center[1], mouseX - center[0])) / Math.PI + 90; diff --git a/resources/js/components/ui/icon.tsx b/resources/js/components/ui/icon.tsx deleted file mode 100644 index bb8b3a06..00000000 --- a/resources/js/components/ui/icon.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { LucideIcon } from 'lucide-react'; - -interface IconProps { - iconNode?: LucideIcon | null; - className?: string; -} - -export function Icon({ iconNode: IconComponent, className }: IconProps) { - if (!IconComponent) { - return null; - } - - return ; -} diff --git a/resources/js/components/ui/input-group.tsx b/resources/js/components/ui/input-group.tsx deleted file mode 100644 index 2dab395c..00000000 --- a/resources/js/components/ui/input-group.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import * as React from 'react'; - -import { cn } from '@/lib/utils'; - -const InputGroup = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => { - return ( -
- ); -}); -InputGroup.displayName = 'InputGroup'; - -const InputGroupAddon = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & { - align?: 'inline-start' | 'inline-end' | 'block-end'; - } ->(({ className, align = 'inline-start', ...props }, ref) => { - return ( -
- ); -}); -InputGroupAddon.displayName = 'InputGroupAddon'; - -const InputGroupText = React.forwardRef< - HTMLSpanElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => { - return ( - - ); -}); -InputGroupText.displayName = 'InputGroupText'; - -const InputGroupInput = React.forwardRef< - HTMLInputElement, - React.InputHTMLAttributes ->(({ className, type = 'text', ...props }, ref) => { - return ( - - ); -}); -InputGroupInput.displayName = 'InputGroupInput'; - -const InputGroupTextarea = React.forwardRef< - HTMLTextAreaElement, - React.TextareaHTMLAttributes ->(({ className, ...props }, ref) => { - return ( -