+
+
+ actions.setSearch(event.target.value)}
+ placeholder="Поиск по заявлениям"
+ className="app-input w-full rounded-lg py-2.5 pl-9 pr-3 text-sm"
+ />
- {state.filtersOpen ? (
-
-
-
+
-
+
+
+
+
+
+
-
+ {state.filtersOpen ? (
+
+
-
+
+
+
+
+
+
+
+
+
+ actions.setCreatedFromFilter(event.target.value)}
+ className="app-input flex-1 rounded-lg px-3 py-2 text-sm"
+ />
+ actions.setCreatedToFilter(event.target.value)}
+ className="app-input flex-1 rounded-lg px-3 py-2 text-sm"
+ />
-
-
-
- {state.hasActiveFilters ? (
-
-
-
- ) : null}
- ) : null}
-
-
+
+
+
+ {state.hasActiveFilters ? (
+
+ ) : null}
+
+ ) : null}
+ >
);
}
diff --git a/frontend/src/components/requests/RequestListItem.tsx b/frontend/src/components/requests/RequestListItem.tsx
index eaacbbbe..4570fa7d 100644
--- a/frontend/src/components/requests/RequestListItem.tsx
+++ b/frontend/src/components/requests/RequestListItem.tsx
@@ -5,7 +5,7 @@ import {
statusMeta,
type RequestAttachmentPreview,
} from "@/hooks/useRequestsPage";
-import { displayUserName, formatDate, formatDateTime, userProfileLink } from "@/lib/shared";
+import { displayUserName, formatDate, userProfileLink } from "@/lib/shared";
import type { Request, RequestComment, User } from "@/types/api";
import {
Ban,
@@ -18,7 +18,7 @@ import {
ThumbsUp,
Trash2,
} from "lucide-react";
-import type { ReactNode, Ref } from "react";
+import type { Ref } from "react";
import { RequestAvatar } from "./RequestAvatar";
import { RequestUserBadge } from "./RequestUserBadge";
@@ -49,64 +49,8 @@ type RequestListItemProps = {
rowOpen: boolean;
};
-type RequestMetaFieldProps = {
- label: string;
- value: ReactNode;
-};
-
-type RequestAudienceRowProps = {
- count?: number;
- currentUserId?: number | null;
- emptyText: string;
- label: string;
- people: User[];
-};
-
-function RequestMetaField({ label, value }: RequestMetaFieldProps) {
- return (
-
- );
-}
-
-function RequestAudienceRow({
- count,
- currentUserId,
- emptyText,
- label,
- people,
-}: RequestAudienceRowProps) {
- return (
-
-
{label}
- {people.length > 0 ? (
-
- {people.slice(0, 2).map((person) => (
-
- ))}
- {people.length > 2 ? (
-
- +{people.length - 2}
-
- ) : null}
-
- ) : (
-
{count ? count : emptyText}
- )}
-
- );
-}
-
function renderDecisionMaker(decisionMaker: User | undefined, currentUserId?: number | null) {
- if (!decisionMaker) {
- return
-;
- }
+ if (!decisionMaker) return
—;
const decisionMakerLink = userProfileLink(decisionMaker, currentUserId);
const decisionMakerName = displayUserName(decisionMaker);
@@ -149,10 +93,10 @@ export function RequestListItem({
const requestAuthor = request.employee || request.created_by;
const authorName = displayUserName(requestAuthor);
const authorFallback = (requestAuthor?.first_name?.[0] || requestAuthor?.last_name?.[0] || "?").toUpperCase();
- const authorLink = requestAuthor ? userProfileLink(requestAuthor, currentUserId) : null;
const statusKey = String(request.status || "").toLowerCase();
- const status = statusMeta[statusKey] ?? defaultStatusMeta;
const typeKey = String(request.type || request.request_type || "").toLowerCase();
+ const status = statusMeta[statusKey] ?? defaultStatusMeta;
+ const authorLink = requestAuthor ? userProfileLink(requestAuthor, currentUserId) : null;
const typeLabel = requestTypeLabels[typeKey] || String(request.type || request.request_type || "Другое");
const title = request.display_title || request.title || "Без заголовка";
const canProcess = Boolean(statusKey === "pending" && request.can_decide);
@@ -162,35 +106,30 @@ export function RequestListItem({
const canDelete = Boolean(isAuthor && !isFinal(statusKey));
const hasSecondaryActions = canCancel || canEdit || canDelete;
const canComment = statusKey !== "draft";
- const summary = request.comment || request.description;
- const commentCount = request.comments_count ?? comments.length;
- const trimmedCommentDraft = commentDraft.trim();
- const recipients = request.recipients || [];
- const ccUsers = request.cc_users || [];
- const decisionMaker = request.approver || request.assigned_to;
const departmentLabels = (request.departments || [])
.map((id) => departmentNameMap.get(Number(id)) || `Отдел #${id}`)
.join(", ");
+ const recipients = request.recipients || [];
+ const ccUsers = request.cc_users || [];
+ const summary = request.comment || request.description;
const attachmentUrl = request.attachment_url || request.attachment || "";
const attachmentName = attachmentUrl
? decodeURIComponent(attachmentUrl.split("/").pop() || "Вложение")
: "";
- const hasExpandedPanels = rowOpen || commentsOpen;
+ const commentCount = request.comments_count ?? comments.length;
+ const decisionMaker = request.approver || request.assigned_to;
return (
-
+
@@ -199,7 +138,7 @@ export function RequestListItem({
title={canComment ? `Комментарии (${commentCount})` : "Комментарии для черновика недоступны"}
onClick={() => canComment && void onToggleComments(request.id)}
disabled={!canComment}
- className={`relative inline-flex h-8 w-8 items-center justify-center rounded-lg transition disabled:cursor-not-allowed disabled:opacity-50 ${commentsOpen ? "app-selected app-accent-text" : "app-action-secondary"}`}
+ className="app-action-secondary relative inline-flex h-8 w-8 items-center justify-center rounded-lg disabled:cursor-not-allowed disabled:opacity-50"
>
{commentCount > 0 ? (
@@ -212,8 +151,8 @@ export function RequestListItem({
-
-
+
+
{authorLink ? (
{authorName}
)}
-
- {typeLabel}
+
+
+
+
+
+
+ Период: {request.date_from ? formatDate(request.date_from) : "—"}
+ {request.date_to ? ` — ${formatDate(request.date_to)}` : ""}
-
-
-
-
-
-
- Период: {request.date_from ? formatDate(request.date_from) : "-"}
- {request.date_to ? ` - ${formatDate(request.date_to)}` : ""}
-
- Создано: {formatDate(request.created_at) || "-"}
-
-
-
- {summary ? (
-
- {summary}
-
- ) : null}
-
-
+
+
{status.label}
-
- {canProcess ? (
- <>
-
-
- >
- ) : null}
-
{hasSecondaryActions ? (
- {hasExpandedPanels ? (
-
-
- {rowOpen ? (
-
-
-
- Подробности
-
- {attachmentUrl ? (
-
- ) : null}
-
+ {summary ? (
+
+ {summary}
+
+ ) : null}
-
-
-
-
-
- -}
- />
-
-
-
-
-
-
-
-
- ) : null}
-
- {commentsOpen ? (
-
-
-
- Комментарии
-
-
- {commentCount}
-
-
-
-
- {comments.length === 0 ? (
-
- Комментариев пока нет
-
- ) : comments.map((comment) => (
-
-
-
{displayUserName(comment.author)}
-
-
- {formatDateTime(comment.created_at) || "-"}
-
- {Boolean(comment.author?.id && currentUserId === comment.author.id) ? (
-
- ) : null}
-
-
-
- {comment.text}
-
-
- ))}
-
-
-
- onSetCommentDraft(request.id, event.target.value)}
- placeholder="Добавить комментарий"
- className="app-input flex-1 rounded-lg px-3 py-2.5 text-sm"
- />
-
-
-
- ) : null}
-
+ {canProcess ? (
+
+
+
+
+
) : null}
+
+ {(rowOpen || commentsOpen) ? (
+
+ {rowOpen ? (
+
+
+
+ Принял решение:{" "}
+ {renderDecisionMaker(decisionMaker, currentUserId)}
+
+
+ Создано:{" "}
+
+ {formatDate(request.created_at) || "—"}
+
+
+
+ Обновлено:{" "}
+
+ {formatDate(request.updated_at) || "—"}
+
+
+ {departmentLabels ? (
+
+ Отделы:{" "}
+ {departmentLabels}
+
+ ) : null}
+
+
+
+
+
Получатели:
+
+ {recipients.slice(0, 2).map((recipient) => (
+
+ ))}
+ {recipients.length === 0 ? (
+ {request.recipient_count ?? 0}
+ ) : null}
+ {recipients.length > 2 ? (
+
+ +{recipients.length - 2}
+
+ ) : null}
+
+
+
+
+
В копии:
+
+ {ccUsers.slice(0, 2).map((ccUser) => (
+
+ ))}
+ {ccUsers.length === 0 ? — : null}
+ {ccUsers.length > 2 ? (
+
+ +{ccUsers.length - 2}
+
+ ) : null}
+
+
+
+ {attachmentUrl ? (
+
+
+
+ ) : null}
+
+
+ ) : null}
+
+ {commentsOpen ? (
+
+
+ {comments.length === 0 ? (
+
Комментариев пока нет
+ ) : (
+ comments.map((comment) => (
+
+
+
{displayUserName(comment.author)}
+
+ {formatDate(comment.created_at)}
+ {Boolean(comment.author?.id && currentUserId === comment.author.id) ? (
+
+ ) : null}
+
+
+
{comment.text}
+
+ ))
+ )}
+
+
+ onSetCommentDraft(request.id, event.target.value)}
+ placeholder="Добавить комментарий"
+ className="app-input flex-1 rounded-lg px-3 py-2 text-xs"
+ />
+
+
+
+ ) : null}
+
+ ) : null}
);
diff --git a/frontend/src/components/requests/RequestListSection.tsx b/frontend/src/components/requests/RequestListSection.tsx
index 2cc1500d..dc7d946c 100644
--- a/frontend/src/components/requests/RequestListSection.tsx
+++ b/frontend/src/components/requests/RequestListSection.tsx
@@ -65,7 +65,7 @@ export function RequestListSection({
}: RequestListSectionProps) {
return (
<>
-
+
{requests.length === 0 ? (