@@ -22,7 +22,7 @@ import Chat from "./components/Chat/Chat";
2222import { uploadAttachmentFx } from "@/store/attachments" ;
2323import { Bug as BugType } from "@/types/bug" ;
2424import Result from "./components/Result/Result" ;
25- import { ChangeEvent } from "react" ;
25+ import { ChangeEvent , useEffect , useRef } from "react" ;
2626import Heading from "./components/Heading/Heading" ;
2727
2828type BugProps = {
@@ -49,8 +49,9 @@ const Bug = ({ reportId, isNewReport, bugId }: BugProps) => {
4949 ] ) ;
5050
5151 const [ newBugData , updateNewBugData ] = useUnit ( [ $newBugStore , updateNewBug ] ) ;
52-
5352 const [ reportRequestState ] = useUnit ( [ $reportRequestState ] ) ;
53+ const receivedTextareaRef = useRef < HTMLTextAreaElement > ( null ) ;
54+ const expectedTextareaRef = useRef < HTMLTextAreaElement > ( null ) ;
5455
5556 const bug = useStoreMap ( {
5657 store : $bugsByBugId ,
@@ -71,6 +72,37 @@ const Bug = ({ reportId, isNewReport, bugId }: BugProps) => {
7172 } ,
7273 } ) ;
7374
75+ useEffect ( ( ) => {
76+ const root = document . documentElement ;
77+ const rawCssVar = getComputedStyle ( root ) . getPropertyValue ( "--spacing" ) ;
78+ const spacing = parseFloat ( rawCssVar ) ;
79+ // вычисляем значение паддинга у <textarea />
80+ // 3 -- потому что className p-3 у <textarea />
81+ const calculatedTextareaPaddingEm = spacing * 3 ;
82+
83+ if ( receivedTextareaRef . current && expectedTextareaRef . current ) {
84+ const fontSizePx = parseFloat (
85+ getComputedStyle ( receivedTextareaRef . current ) . fontSize
86+ ) ;
87+ const calculatedTextareaPaddingPx =
88+ calculatedTextareaPaddingEm * fontSizePx ;
89+ const textareaReceiveScrollHeight = `${
90+ receivedTextareaRef . current . scrollHeight + calculatedTextareaPaddingPx
91+ } px`;
92+ const textareaExpectScrollHeight = `${
93+ expectedTextareaRef . current . scrollHeight + calculatedTextareaPaddingPx
94+ } px`;
95+
96+ if ( textareaReceiveScrollHeight >= textareaExpectScrollHeight ) {
97+ receivedTextareaRef . current . style . height = textareaReceiveScrollHeight ;
98+ expectedTextareaRef . current . style . height = "100%" ;
99+ } else {
100+ expectedTextareaRef . current . style . height = textareaExpectScrollHeight ;
101+ receivedTextareaRef . current . style . height = "100%" ;
102+ }
103+ }
104+ } , [ receivedTextareaRef , expectedTextareaRef , newBugData , bug ] ) ;
105+
74106 const attachments = useStoreMap ( {
75107 store : $attachmentsByBugId ,
76108 keys : [ bugId ] ,
@@ -143,64 +175,62 @@ const Bug = ({ reportId, isNewReport, bugId }: BugProps) => {
143175
144176 return (
145177 < div
146- className = { `card card-border p-4 mb-3 shadow-lg border-gray-300 ${
178+ className = { `card card-border grid grid-cols-2 gap-2 p-4 mb-3 shadow-lg border-gray-300 ${
147179 bug . status === Number ( BugStatuses . READY ) ? "border-success" : ""
148180 } `}
149181 >
150- < div className = "gap-2 flex flex-col" >
151- < div className = "flex items-center justify-between" >
152- { reportRequestState !== RequestStates . DONE ? (
153- < div className = "skeleton min-h-[2em] min-w-[30%] shrink-0" />
154- ) : (
155- < Heading isNewBug = { isNewBug } bugId = { bug . id } />
156- ) }
157-
158- { /* Селект статуса (только для существующего бага) */ }
159- { ! isNewBug && reportRequestState === RequestStates . DONE && (
160- < Dropdown
161- className = "max-w-[150px]"
162- onChange = { ( selected ) => {
163- if ( bug . id ) {
164- updateBugData ( { id : bug . id , status : Number ( selected ) } ) ;
165- }
166- } }
167- value = { bug . status }
168- options = { [
169- { label : "Исправлен" , value : BugStatuses . READY } ,
170- { label : "Открыт" , value : BugStatuses . IN_PROGRESS } ,
171- ] }
172- />
173- ) }
174- { reportRequestState !== RequestStates . DONE && (
175- < div className = "skeleton min-h-[40px] min-w-[30%] shrink-0" />
176- ) }
177- </ div >
178- < div className = "flex grow-1 gap-2" >
179- < Result
180- title = "Фактический результат"
181- value = { isNewBug ? newBugData . receive : bug ?. receive || "" }
182- onChange = { ( event ) => handleResultUpdate ( event , "receive" ) }
183- files = { receivedFiles }
184- onFileChange = { ( event ) =>
185- handleFileChange ( event , AttachmentTypes . RECEIVED_RESULT )
186- }
187- withAttachments = { ! isNewBug }
188- />
189- < Result
190- title = "Ожидаемый результат"
191- value = { isNewBug ? newBugData . expect : bug ?. expect || "" }
192- onChange = { ( event ) => handleResultUpdate ( event , "expect" ) }
193- files = { expectedFiles }
194- onFileChange = { ( event ) =>
195- handleFileChange ( event , AttachmentTypes . EXPECTED_RESULT )
196- }
197- withAttachments = { ! isNewBug }
182+ < div className = "flex items-center justify-between col-span-2" >
183+ { reportRequestState !== RequestStates . DONE ? (
184+ < div className = "skeleton min-h-[2em] min-w-[30%] shrink-0" />
185+ ) : (
186+ < Heading isNewBug = { isNewBug } bugId = { bug . id } />
187+ ) }
188+
189+ { /* Селект статуса (только для существующего бага) */ }
190+ { ! isNewBug && reportRequestState === RequestStates . DONE && (
191+ < Dropdown
192+ className = "max-w-[150px]"
193+ onChange = { ( selected ) => {
194+ if ( bug . id ) {
195+ updateBugData ( { id : bug . id , status : Number ( selected ) } ) ;
196+ }
197+ } }
198+ value = { bug . status }
199+ options = { [
200+ { label : "Исправлен" , value : BugStatuses . READY } ,
201+ { label : "Открыт" , value : BugStatuses . IN_PROGRESS } ,
202+ ] }
198203 />
199- </ div >
204+ ) }
205+ { reportRequestState !== RequestStates . DONE && (
206+ < div className = "skeleton min-h-[40px] min-w-[30%] shrink-0" />
207+ ) }
200208 </ div >
209+ < Result
210+ title = "Фактический результат"
211+ value = { isNewBug ? newBugData . receive : bug ?. receive || "" }
212+ onChange = { ( event ) => handleResultUpdate ( event , "receive" ) }
213+ files = { receivedFiles }
214+ onFileChange = { ( event ) =>
215+ handleFileChange ( event , AttachmentTypes . RECEIVED_RESULT )
216+ }
217+ withAttachments = { ! isNewBug }
218+ textareaRef = { receivedTextareaRef }
219+ />
220+ < Result
221+ title = "Ожидаемый результат"
222+ value = { isNewBug ? newBugData . expect : bug ?. expect || "" }
223+ onChange = { ( event ) => handleResultUpdate ( event , "expect" ) }
224+ files = { expectedFiles }
225+ onFileChange = { ( event ) =>
226+ handleFileChange ( event , AttachmentTypes . EXPECTED_RESULT )
227+ }
228+ withAttachments = { ! isNewBug }
229+ textareaRef = { expectedTextareaRef }
230+ />
201231 { /* Кнопки "Сохранить" / "Отмена" */ }
202232 { ! isNewReport && isBugChanged && (
203- < div className = "flex gap-2 justify-end mt-2" >
233+ < div className = "flex gap-2 justify-end mt-2 col-span-2 " >
204234 < CancelButton
205235 isChanged = { isBugChanged }
206236 onReset = { ( ) => {
@@ -220,7 +250,7 @@ const Bug = ({ reportId, isNewReport, bugId }: BugProps) => {
220250 </ div >
221251 ) }
222252 { ! isNewBug && (
223- < div className = "mt-2" >
253+ < div className = "mt-2 col-span-2 " >
224254 < Chat reportId = { bug . reportId ! } bugId = { bug . id ! } />
225255 </ div >
226256 ) }
0 commit comments