feat(değerlendirme): dönem kapatma sihirbazı
- /degerlendirme/kapat: Özet → Birikim → Onay → Sonuç - Birikime aktarılacak tutar (varsayılan tamamı), kalan artı/açık devri önizlemesi - Değerlendirme sayfasına "Dönemi Kapat" bölümü - Yeni dönem önerisi son dönemin bitişinden başlar (erken kapatılan ay önerilmez) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,10 @@ import { FormError, FormField } from '@/components/form-field'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { ApiError } from '@/lib/api'
|
||||
import { daysInclusive, isIsoDate, lastToEnd, monthRange } from '@/lib/period-dates'
|
||||
import { useCreatePeriod, useUpdatePeriod } from '@/lib/periods'
|
||||
import { PageError, PageLoading } from '@/components/page'
|
||||
import { formatDate } from '@/lib/format'
|
||||
import { daysInclusive, isIsoDate, lastToEnd, suggestRanges } from '@/lib/period-dates'
|
||||
import { useCreatePeriod, usePeriods, useUpdatePeriod } from '@/lib/periods'
|
||||
import { t } from '@/lib/strings'
|
||||
import type { Period } from '@/types/Period'
|
||||
import { datesSchema, type DatesForm } from './schemas'
|
||||
@@ -17,15 +19,45 @@ const s = t.wizard.dates
|
||||
|
||||
const monthName = new Intl.DateTimeFormat('tr-TR', { month: 'long', year: 'numeric' })
|
||||
|
||||
/** 1. adım: dönem yoksa açar, varsa (geri gelindiyse) günceller. */
|
||||
/** Hızlı seçim etiketi: takvim ayıysa "Aralık 2026", değilse "15.11.2026 – 14.12.2026" */
|
||||
function rangeLabel(r: { start: string; last: string }) {
|
||||
const [y, m, d] = r.start.split('-').map(Number)
|
||||
const monthEnd = new Date(Date.UTC(y, m, 0)).toISOString().slice(0, 10)
|
||||
return d === 1 && r.last === monthEnd
|
||||
? monthName.format(new Date(y, m - 1, 1))
|
||||
: `${formatDate(r.start)} – ${formatDate(r.last)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. adım: dönem yoksa açar, varsa (geri gelindiyse) günceller.
|
||||
* Öneriler son dönemin bitişinden başlar (erken kapatılan ay tekrar önerilmez).
|
||||
*/
|
||||
export function StepDates({ period, onDone }: { period: Period | null; onDone: () => void }) {
|
||||
const periods = usePeriods()
|
||||
if (periods.isPending) return <PageLoading />
|
||||
if (periods.isError)
|
||||
return <PageError message={periods.error.message} onRetry={periods.refetch} />
|
||||
// Liste en yeni başta; sihirbazda açık dönem varsa (geri gelindi) o hariç tutulur
|
||||
const previous = periods.data.find((p) => p.id !== period?.id)
|
||||
return <DatesStepForm period={period} prevEnd={previous?.end_date} onDone={onDone} />
|
||||
}
|
||||
|
||||
function DatesStepForm({
|
||||
period,
|
||||
prevEnd,
|
||||
onDone,
|
||||
}: {
|
||||
period: Period | null
|
||||
prevEnd?: string
|
||||
onDone: () => void
|
||||
}) {
|
||||
const create = useCreatePeriod()
|
||||
const update = useUpdatePeriod()
|
||||
|
||||
const [today] = useState(() => new Date()) // render başına değil, bir kez
|
||||
const presets = [0, 1].map((offset) => ({
|
||||
label: monthName.format(new Date(today.getFullYear(), today.getMonth() + offset, 1)),
|
||||
range: monthRange(today, offset),
|
||||
const presets = suggestRanges(today, prevEnd).map((range) => ({
|
||||
label: rangeLabel(range),
|
||||
range,
|
||||
}))
|
||||
|
||||
const {
|
||||
|
||||
Reference in New Issue
Block a user