Files
no-copy-frontend/src/app/ui/file-page/violation-table/case-complaint.tsx
T
2026-06-08 13:27:30 +07:00

405 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { ViolationFileDetail } from '@/app/hooks/react-query/useFileViolations';
import { useActionState, useEffect, useState, SetStateAction } from 'react';
import { useTranslations } from 'next-intl';
import { createComplaint, fetchComplainInfo, MatchStatus } from '@/app/actions/violationActions';
import { toast } from 'sonner';
import { useQuery } from '@tanstack/react-query';
import { formatDate, formatDateTime } from '@/app/lib/formatDate';
import ModalWindow from '@/app/components/ModalWindow';
interface complaintInfo {
id: number,
status: string,
complaint_text: string,
violation_id: number,
email: string,
created_at: string,
updated_at: string,
not_moderated: boolean
}
const ENABLED_STATUSES = ['COMPLAINT_IN_WORK', 'COMPLAINT_AND_LEGAL_IN_WORK'];
type UpdateStatusHandler = (id: number, status: MatchStatus) => Promise<boolean>;
export default function CaseComplaint({ selectedViolation, updateStatusHandler, setLocalViolation }:
{
selectedViolation: ViolationFileDetail,
updateStatusHandler: UpdateStatusHandler,
setLocalViolation: React.Dispatch<SetStateAction<ViolationFileDetail>>
}
) {
const t = useTranslations('Global');
const [noteText, setNoteText] = useState('');
const [state, formAction, isPending] = useActionState(createComplaint, undefined);
const [isTemplateModalOpen, setIsTemplateModalOpen] = useState(false);
const [templateName, setTemplateName] = useState('');
const { data: complainInfo, isLoading: isLoadingComplain } = useQuery({
queryKey: ['complainInfo', selectedViolation.id],
queryFn: () => fetchComplainInfo(selectedViolation.id),
select: (data) => {
if (data) {
return data
}
},
enabled: ENABLED_STATUSES.includes(selectedViolation.status),
});
useEffect(() => {
if (state?.success) {
toast.success(t('the-complaint-has-been-registered'));
const newStatus = selectedViolation.status === 'LEGAL_IN_WORK'
? 'COMPLAINT_AND_LEGAL_IN_WORK'
: 'COMPLAINT_IN_WORK';
setLocalViolation(prev => ({
...prev,
status: newStatus
}))
updateStatusHandler(selectedViolation.id, newStatus);
} else if (state && !state.success) {
console.log(state.errorMessage);
if (state.errorMessage?.server) {
toast.warning(t(state.errorMessage.server));
} else {
toast.warning(t('the-complaint-has-not-been-registered'));
}
}
}, [state, updateStatusHandler, selectedViolation.id]);
function templateHandler(e: React.MouseEvent<HTMLLIElement>) {
const sampleItemText = e.currentTarget.querySelector('.sample-item-text');
if (sampleItemText) {
const text = sampleItemText.textContent || '';
setNoteText(text);
}
}
function openTemplateSaveModal() {
if (!noteText.trim()) {
toast.warning(t('please-enter-complaint-text-first'));
return;
}
setTemplateName('');
setIsTemplateModalOpen(true);
}
function saveTemplateHandler() {
if (!templateName.trim()) {
toast.warning(t('please-enter-template-name'));
return;
}
// пока нету эндпоинта оставлю заглушку
console.log('СОХРАНЕНИЕ ШАБЛОНА');
console.log('Название шаблона:', templateName);
console.log('Текст жалобы:', noteText);
console.log('========================');
toast.success(t('template-saved-successfully') || 'Шаблон успешно сохранен');
setIsTemplateModalOpen(false);
setTemplateName('');
}
if (!ENABLED_STATUSES.includes(selectedViolation.status)) {
return (
<>
<div className="violation-info-case">
<div className="note-form">
<form action={formAction}>
<input type="hidden" name="violationId" value={selectedViolation.id} />
<section
className="note-form-section"
>
<div
className="note-form-group"
>
<label
className="note-case-label"
htmlFor="note"
>
{t('text-of-the-complaint')}
</label>
<textarea
name="note"
className="note-textarea"
placeholder={`${t('text-area-error-fill-complaint-text')}...`}
value={noteText}
onChange={(e) => setNoteText(e.target.value)}
>
</textarea>
</div>
{state?.errorMessage?.textArea && (
<p
className="text-sm text-red-500"
>
{
state?.errorMessage?.textArea.split('&').map((e, index) => {
return (
<span key={index}>
{t(e)}
<br />
</span>
)
})
}
</p>
)}
</section>
<div
className="button-actions"
>
{/* пока скроем интерфейс с шаблонами */}
{/* <button
type="button"
className="btn-s btn-primary-small"
onClick={openTemplateSaveModal}
>
{t('save-template')}
</button> */}
<button
type="submit"
className="btn-s btn-primary-small"
disabled={isPending}
>
{t('submit-violation')}
</button>
</div>
</form>
</div>
{/* пока скроем интерфейс с шаблонами */}
{/* <div
className="samples-wrapper"
>
<h5>Шаблоны</h5>
<ul
className="samples-list"
>
<li
className="sample-item"
onClick={(e) => {
templateHandler(e)
}}
>
<div
className="sample-item-title"
>
title 1
</div>
<div
className="sample-item-text"
>
1text text text text text text text text text text text text
</div>
</li>
<li
className="sample-item"
onClick={(e) => {
templateHandler(e)
}}
>
<div
className="sample-item-title"
>
title 2
</div>
<div
className="sample-item-text"
>
2text text text text text text text text text text text text
</div>
</li>
<li
className="sample-item"
onClick={(e) => {
templateHandler(e)
}}
>
<div
className="sample-item-title"
>
title 3
</div>
<div
className="sample-item-text"
>
3text text text text text text text text text text text text
</div>
</li>
<li
className="sample-item"
onClick={(e) => {
templateHandler(e)
}}
>
<div
className="sample-item-title"
>
title 3
</div>
<div
className="sample-item-text"
>
3text text text text text text text text text text text text
</div>
</li>
<li
className="sample-item"
onClick={(e) => {
templateHandler(e)
}}
>
<div
className="sample-item-title"
>
title 3
</div>
<div
className="sample-item-text"
>
3text text text text text text text text text text text text
</div>
</li>
</ul>
</div> */}
</div>
<ModalWindow
state={isTemplateModalOpen}
callBack={setIsTemplateModalOpen}
>
<div className="template-modal-content">
<div className="template-modal-header">
<h3>{t('save-template')}</h3>
<button
className="template-modal-close"
onClick={() => setIsTemplateModalOpen(false)}
>
×
</button>
</div>
<div className="template-modal-body">
<div className="template-form-group">
<label htmlFor="templateName">
{t('template-name')}:
</label>
<input
id="templateName"
type="text"
className="template-name-input"
placeholder={t('enter-template-name')}
value={templateName}
onChange={(e) => setTemplateName(e.target.value)}
autoFocus
/>
</div>
<div className="template-preview">
<div className="template-preview-label">
{t('complaint-text-preview')}
</div>
<div className="template-preview-text">
{noteText || t('no-text')}
</div>
</div>
</div>
<div className="template-modal-footer">
<button
className="btn-s btn-primary-small"
onClick={() => setIsTemplateModalOpen(false)}
>
{t('cancel')}
</button>
<button
className="btn-s btn-resolve"
onClick={saveTemplateHandler}
>
{t('save')}
</button>
</div>
</div>
</ModalWindow>
</>
);
} else {
if (isLoadingComplain) {
return (
<div className="violation-info-case">
<div
className="loading-animation"
>
<div
className="global-spinner large"
>
</div>
</div>
</div>
);
}
return (
<div className="violation-info-case">
{complainInfo?.body ? (
<div>
<div className="complaint-details">
<div className="complaint-details-item">
<div className="complaint-details-header">
<h5>COM-{complainInfo.body?.id}</h5>
</div>
</div>
<div className="complaint-details-item">
<div className="complaint-details-title">{t('Status')}:</div>
<div className="complaint-details-content">
{complainInfo.body?.status}
</div>
</div>
<div className="complaint-details-item">
<div className="complaint-details-title">{t('date-of-creation')}:</div>
<div className="complaint-details-content">
{complainInfo.body?.created_at
? `${formatDate(complainInfo.body.created_at)}: ${formatDateTime(complainInfo.body.created_at)}`
: '---'}
</div>
</div>
<div className="complaint-details-item">
<div className="complaint-details-title">{t('date-of-update')}:</div>
<div className="complaint-details-content">
{complainInfo.body?.updated_at
? `${formatDate(complainInfo.body.updated_at)}: ${formatDateTime(complainInfo.body.updated_at)}`
: '---'}
</div>
</div>
<div className="complaint-details-item">
<div className="complaint-details-title">{t('text-of-the-complaint')}:</div>
<div className="complaint-details-content">
{complainInfo.body?.complaint_text}
</div>
</div>
</div>
</div>
) : (
<div>
{t('no-information-about-the-complaint')}
</div>
)}
</div>
);
}
}