feat: UI polish, lint fixes, onboarding redesign, help page expansion, and test improvements
Broad update across dashboard pages, components, extensions, and lib code. Includes ESLint config additions, onboarding flow redesign, settings page refactor, help page content expansion, dead code removal, and test mock fixes. Adds dev docs and public assets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
02ebe50f52
commit
091d043c85
@@ -29,10 +29,6 @@ export default function ChartOfAccounts() {
|
||||
const [editingSRU, setEditingSRU] = useState<string | null>(null)
|
||||
const [sruValue, setSruValue] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
fetchAccounts()
|
||||
}, [])
|
||||
|
||||
async function fetchAccounts() {
|
||||
const res = await fetch('/api/bookkeeping/accounts')
|
||||
const { data } = await res.json()
|
||||
@@ -40,6 +36,10 @@ export default function ChartOfAccounts() {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchAccounts()
|
||||
}, [])
|
||||
|
||||
async function updateSRUCode(accountId: string, newSruCode: string) {
|
||||
const supabase = createClient()
|
||||
const trimmed = newSruCode.trim() || null
|
||||
|
||||
@@ -70,11 +70,6 @@ export default function JournalEntryForm({
|
||||
uploadedFiles.length > 0
|
||||
useUnsavedChanges(hasContent)
|
||||
|
||||
useEffect(() => {
|
||||
fetchPeriods()
|
||||
fetchAccounts()
|
||||
}, [])
|
||||
|
||||
async function fetchPeriods() {
|
||||
const res = await fetch('/api/bookkeeping/fiscal-periods')
|
||||
const { data } = await res.json()
|
||||
@@ -90,6 +85,11 @@ export default function JournalEntryForm({
|
||||
setAccounts(data || [])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchPeriods()
|
||||
fetchAccounts()
|
||||
}, [])
|
||||
|
||||
const addLine = () => {
|
||||
setLines([...lines, { ...BLANK_LINE }])
|
||||
}
|
||||
|
||||
@@ -49,10 +49,6 @@ export default function JournalEntryList({ periodId }: Props) {
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
fetchEntries()
|
||||
}, [periodId, page])
|
||||
|
||||
async function fetchEntries() {
|
||||
setLoading(true)
|
||||
const params = new URLSearchParams({
|
||||
@@ -73,6 +69,10 @@ export default function JournalEntryList({ periodId }: Props) {
|
||||
fetchAttachmentCounts(ids)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchEntries()
|
||||
}, [periodId, page])
|
||||
|
||||
const handleAttachmentCountChange = useCallback((entryId: string, count: number) => {
|
||||
setAttachmentCounts((prev) => ({ ...prev, [entryId]: count }))
|
||||
}, [])
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ChatMessage } from './ChatMessage'
|
||||
import { ChatInput } from './ChatInput'
|
||||
import { useChatStream } from './useChatStream'
|
||||
import { useToast } from '@/components/ui/use-toast'
|
||||
import { Bot, Trash2, RotateCcw } from 'lucide-react'
|
||||
import { Bot, RotateCcw } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
interface ChatPanelProps {
|
||||
@@ -20,7 +20,7 @@ export function ChatPanel({ className }: ChatPanelProps) {
|
||||
messages,
|
||||
isLoading,
|
||||
isStreaming,
|
||||
error,
|
||||
error: _error,
|
||||
toolsExecuting,
|
||||
sendMessage,
|
||||
clearChat,
|
||||
|
||||
@@ -18,8 +18,6 @@ interface ChatAgingBucketsProps {
|
||||
export function ChatAgingBuckets({ artifact }: ChatAgingBucketsProps) {
|
||||
const { title, buckets, total } = artifact
|
||||
|
||||
const maxAmount = Math.max(...buckets.map((b) => b.amount), 1)
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex items-baseline justify-between mb-3">
|
||||
|
||||
@@ -6,7 +6,7 @@ interface ChatDataTableProps {
|
||||
artifact: TableArtifact
|
||||
}
|
||||
|
||||
function formatCell(value: string | number, align?: 'left' | 'right'): string {
|
||||
function formatCell(value: string | number, _align?: 'left' | 'right'): string {
|
||||
if (typeof value === 'number') {
|
||||
return new Intl.NumberFormat('sv-SE', {
|
||||
minimumFractionDigits: value % 1 !== 0 ? 2 : 0,
|
||||
|
||||
@@ -8,6 +8,7 @@ import ExtensionToggleButton from './ExtensionToggleButton'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function ExtensionCard({ extension }: { extension: ExtensionDefinition }) {
|
||||
|
||||
const Icon = resolveIcon(extension.icon)
|
||||
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,7 @@ export default function ExtensionWorkspaceLoader({
|
||||
definition: ExtensionDefinition
|
||||
userId: string
|
||||
}) {
|
||||
|
||||
const WorkspaceComponent = getWorkspaceComponent(sector, slug)
|
||||
|
||||
return (
|
||||
|
||||
@@ -12,6 +12,7 @@ export default function ExtensionWorkspaceShell({
|
||||
definition: ExtensionDefinition
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
|
||||
const Icon = resolveIcon(definition.icon)
|
||||
const sector = getSector(definition.sector)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { resolveIcon } from '@/lib/extensions/icon-resolver'
|
||||
import type { Sector } from '@/lib/extensions/types'
|
||||
|
||||
export default function SectorCard({ sector }: { sector: Sector }) {
|
||||
|
||||
const Icon = resolveIcon(sector.icon)
|
||||
|
||||
return (
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
XCircle,
|
||||
ArrowRight,
|
||||
RotateCcw,
|
||||
ExternalLink,
|
||||
} from 'lucide-react'
|
||||
import type { IngestResult } from '@/lib/transactions/ingest'
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useState, useCallback } from 'react'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
import {
|
||||
|
||||
@@ -45,15 +45,8 @@ export default function Step1EntityType({ initialData, onNext, isSaving }: Step1
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="text-center">
|
||||
<h1 className="text-3xl font-bold tracking-tight">Välkommen!</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Låt oss börja med att ställa in din verksamhet. Vilken företagsform har du?
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 max-w-lg mx-auto">
|
||||
<div className="space-y-8">
|
||||
<div className="grid gap-3">
|
||||
{entityOptions.map((option) => {
|
||||
const Icon = option.icon
|
||||
const isSelected = selected === option.value
|
||||
|
||||
@@ -57,13 +57,6 @@ export default function Step2CompanyDetails({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="text-center">
|
||||
<h1 className="text-3xl font-bold tracking-tight">Företagsuppgifter</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Fyll i uppgifter om din verksamhet. Dessa används på fakturor.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Grunduppgifter</CardTitle>
|
||||
|
||||
@@ -263,13 +263,6 @@ export default function Step3TaxRegistration({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="text-center">
|
||||
<h1 className="text-3xl font-bold tracking-tight">Skatteregistrering</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Ange information om din skatteregistrering.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>F-skatt och räkenskapsår</CardTitle>
|
||||
|
||||
@@ -50,13 +50,6 @@ export default function Step4PreliminaryTax({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="text-center">
|
||||
<h1 className="text-3xl font-bold tracking-tight">Preliminärskatt</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Ange din månatliga F-skatt för att få bättre överblick över din ekonomi.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
|
||||
@@ -57,14 +57,6 @@ export default function Step6ConnectBank({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="text-center">
|
||||
<h1 className="text-3xl font-bold tracking-tight">Bankuppgifter</h1>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Ange dina bankuppgifter så visas de på dina fakturor.
|
||||
Du kan importera transaktioner från din bank efteråt.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import * as React from "react"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import * as React from "react"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface TextareaProps
|
||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
|
||||
Reference in New Issue
Block a user