diff --git a/frontend/src/components/finance/admin/PayrollAdminModals.tsx b/frontend/src/components/finance/admin/PayrollAdminModals.tsx index bc01e831..60bfaf9a 100644 --- a/frontend/src/components/finance/admin/PayrollAdminModals.tsx +++ b/frontend/src/components/finance/admin/PayrollAdminModals.tsx @@ -34,7 +34,7 @@ import { formatPayrollPoints, normalizePayrollPoints } from "@/lib/payroll"; const inputClass = "app-input w-full rounded-lg px-3 py-2.5 text-sm"; const selectClass = "app-select w-full rounded-lg px-3 py-2.5 text-sm"; -function ModalActions({ +export function ModalActions({ busy, disabled = false, onClose, @@ -71,7 +71,7 @@ function ModalActions({ ); } -function FormError({ message }: { message: string | null }) { +export function FormError({ message }: { message: string | null }) { if (!message) return null; return (
diff --git a/frontend/src/components/finance/admin/PayrollAdminTables.tsx b/frontend/src/components/finance/admin/PayrollAdminTables.tsx index 32e0ebf1..512086c0 100644 --- a/frontend/src/components/finance/admin/PayrollAdminTables.tsx +++ b/frontend/src/components/finance/admin/PayrollAdminTables.tsx @@ -40,17 +40,19 @@ function RecordStatus({ status }: { status: PayrollApprovalStatus }) { ); } -function CompactRecordCard({ +export function CompactRecordCard({ title, subtitle, summary, status, + statusContent, children, }: { title: string; subtitle: string; summary: ReactNode; status: PayrollApprovalStatus; + statusContent?: ReactNode; children: ReactNode; }) { const [open, setOpen] = useState(false); @@ -81,7 +83,7 @@ function CompactRecordCard({ - + {statusContent ?? } {open ? ( @@ -93,7 +95,7 @@ function CompactRecordCard({ ); } -function CompactField({ +export function CompactField({ label, children, }: { @@ -110,7 +112,7 @@ function CompactField({ ); } -function ListState({ +export function ListState({ loading, error, empty, @@ -242,7 +244,7 @@ export function PayrollInputHistory({ ); } -function ActionButton({ +export function ActionButton({ label, icon, onClick, diff --git a/frontend/src/components/finance/admin/PayrollOffCyclePayments.tsx b/frontend/src/components/finance/admin/PayrollOffCyclePayments.tsx index aaa869ef..9203a5b5 100644 --- a/frontend/src/components/finance/admin/PayrollOffCyclePayments.tsx +++ b/frontend/src/components/finance/admin/PayrollOffCyclePayments.tsx @@ -1,8 +1,24 @@ "use client"; import { useCallback, useEffect, useState, type FormEvent } from "react"; -import { Loader2, Plus, RefreshCw, Search } from "lucide-react"; +import { Plus, RefreshCw, RotateCcw, Search } from "lucide-react"; + import { Modal } from "@/components/ui"; +import { CompactFilterMenu } from "@/components/ui/CompactFilterMenu"; +import { ModulePrimaryAction } from "@/components/ui/ModulePrimaryAction"; +import { ProjectSelectMenu } from "@/components/ui/ProjectSelectMenu"; +import { SearchableSelectSingle } from "@/components/shared/SearchableSelect"; +import { + FormError, + ModalActions, + PayrollConfirmModal, +} from "./PayrollAdminModals"; +import { + ActionButton, + CompactField, + CompactRecordCard, + ListState, +} from "./PayrollAdminTables"; import { apiClient } from "@/lib/api"; import type { PayrollAdminEmployee, @@ -12,15 +28,30 @@ import type { PayrollOffCycleSettlement, } from "@/lib/api/finance"; import { getPayrollAdminError } from "@/lib/payroll-admin"; -import { formatPayrollDate, formatPayrollMoney } from "@/lib/payroll"; +import { + formatPayrollDate, + formatPayrollDateTime, + formatPayrollMoney, +} from "@/lib/payroll"; const inputClass = "app-input w-full rounded-lg px-3 py-2.5 text-sm"; +const selectClass = "app-select w-full rounded-lg px-3 py-2.5 text-sm"; function localToday() { const now = new Date(); return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`; } +function PaymentStatus({ payment }: { payment: PayrollOffCyclePayment }) { + return ( + + {payment.voided_at ? "Отменена" : "Выдано"} + + ); +} + function PaymentForm({ employees, periods, @@ -48,13 +79,6 @@ function PaymentForm({ useState(null); const [settlementLoading, setSettlementLoading] = useState(false); const [settlementError, setSettlementError] = useState(null); - const matches = employees - .filter((item) => - item.display_name - .toLocaleLowerCase("ru") - .includes(name.toLocaleLowerCase("ru").trim()), - ) - .slice(0, 8); const sourcePeriod = periods.find( (period) => period.id === Number(sourcePeriodId), ); @@ -126,89 +150,72 @@ function PaymentForm({ onClose={() => { if (!busy) onClose(); }} - title="Добавить выплату вне периода" - size="lg" + title="Новая выплата вне периода" + size="md" > -
-

- Запишите фактически выданные деньги. Расчётные листки и уведомления не - создаются. + +

+ Учёт выданных денег. Расчётные листки и уведомления не отправляются.

- -
- - { - setName(event.target.value); - setEmployee(null); - }} - /> - {!manual && !employee ? ( -
- {matches.map((item) => ( - - ))} - {!matches.length ? ( -

- Совпадений нет. Для ручного ввода включите переключатель выше. -

- ) : null} -
- ) : employee ? ( -

- Выплата будет связана с карточкой сотрудника. -

- ) : null} -
-