@@ -6,13 +6,15 @@ import { useParams } from "react-router-dom";
6
6
import { Descriptions , Tag , Avatar , Skeleton , Button , Typography , List , Table , Progress , Input , Upload , message } from "antd" ;
7
7
import { UploadOutlined } from '@ant-design/icons' ;
8
8
import history from "util/history" ;
9
- import { getTicket , updateTicketDescription , addComment , uploadAttachment } from '@lowcoder-ee/api/supportApi' ; // Placeholder for your API functions
9
+ import { getTicket , updateTicketDescription , addComment , uploadAttachment } from '@lowcoder-ee/api/supportApi' ;
10
10
import { Level1SettingPageContent , Level1SettingPageTitle } from "../setting/styled" ;
11
11
import { HeaderBack } from "../setting/permission/styledComponents" ;
12
12
import { SUPPORT_URL } from "constants/routesURL" ;
13
13
import { TacoMarkDown } from "lowcoder-design" ;
14
14
import remarkGfm from 'remark-gfm' ;
15
15
import { contrastColor } from "comps/controls/styleControlConstants" ;
16
+ import ReactQuill from 'react-quill' ;
17
+ import 'react-quill/dist/quill.snow.css' ;
16
18
17
19
const { Title, Text } = Typography ;
18
20
const { TextArea } = Input ;
@@ -124,6 +126,67 @@ const convertJiraToMarkdown = (content: string) => {
124
126
return content ;
125
127
} ;
126
128
129
+ const convertJiraToHtml = ( content : any ) => {
130
+ // Convert bold text: `*text*` to `<strong>text</strong>`
131
+ content = content . replace ( / \* ( .+ ?) \* / g, '<strong>$1</strong>' ) ;
132
+
133
+ // Convert italic text: `_text_` to `<em>text</em>`
134
+ content = content . replace ( / _ ( .+ ?) _ / g, '<em>$1</em>' ) ;
135
+
136
+ // Convert ordered lists: `# item` to `<ol><li>item</li></ol>`
137
+ content = content . replace ( / (?: ^ | \n ) # \s + ( .* ?) (? = \n | $ ) / g, '<ol><li>$1</li></ol>' ) ;
138
+ content = content . replace ( / < \/ o l > \s * < o l > / g, '' ) ; // Merge consecutive lists
139
+
140
+ // Convert unordered lists: `* item` to `<ul><li>item</li></ul>`
141
+ content = content . replace ( / (?: ^ | \n ) \* \s + ( .* ?) (? = \n | $ ) / g, '<ul><li>$1</li></ul>' ) ;
142
+ content = content . replace ( / < \/ u l > \s * < u l > / g, '' ) ; // Merge consecutive lists
143
+
144
+ // Convert headers: `h1. Header` to `<h1>Header</h1>`
145
+ content = content . replace ( / ^ h 1 \. \s ( .* ?) (? = \n | $ ) / gm, '<h1>$1</h1>' ) ;
146
+ content = content . replace ( / ^ h 2 \. \s ( .* ?) (? = \n | $ ) / gm, '<h2>$1</h2>' ) ;
147
+ content = content . replace ( / ^ h 3 \. \s ( .* ?) (? = \n | $ ) / gm, '<h3>$1</h3>' ) ;
148
+
149
+ // Convert line breaks
150
+ content = content . replace ( / \n / g, '<br>' ) ;
151
+
152
+ return content ;
153
+ } ;
154
+
155
+ // Function to convert HTML to Jira syntax
156
+ const convertHtmlToJiraMarkdown = ( html :any ) => {
157
+ // Convert bold tags to Jira bold
158
+ html = html . replace ( / < s t r o n g > ( .* ?) < \/ s t r o n g > / g, '*$1*' ) ;
159
+
160
+ // Convert italic tags to Jira italic
161
+ html = html . replace ( / < e m > ( .* ?) < \/ e m > / g, '_$1_' ) ;
162
+
163
+ // Convert ordered list items to Jira syntax
164
+ html = html . replace ( / < o l > ( .* ?) < \/ o l > / gs, ( match : any , inner : string ) => {
165
+ return inner . replace ( / < l i > ( .* ?) < \/ l i > / g, '# $1\n' ) ;
166
+ } ) ;
167
+
168
+ // Convert unordered list items to Jira syntax
169
+ html = html . replace ( / < u l > ( .* ?) < \/ u l > / gs, ( match : any , inner : string ) => {
170
+ return inner . replace ( / < l i > ( .* ?) < \/ l i > / g, '* $1\n' ) ;
171
+ } ) ;
172
+
173
+ // Convert headings
174
+ html = html . replace ( / < h 1 > ( .* ?) < \/ h 1 > / g, 'h1. $1' ) ;
175
+ html = html . replace ( / < h 2 > ( .* ?) < \/ h 2 > / g, 'h2. $1' ) ;
176
+ html = html . replace ( / < h 3 > ( .* ?) < \/ h 3 > / g, 'h3. $1' ) ;
177
+
178
+ // Convert paragraphs
179
+ html = html . replace ( / < p > ( .* ?) < \/ p > / g, '$1\n' ) ;
180
+
181
+ // Handle line breaks
182
+ html = html . replace ( / < b r \s * \/ ? > / g, '\n' ) ;
183
+
184
+ // Remove any remaining HTML tags
185
+ html = html . replace ( / < \/ ? [ ^ > ] + ( > | $ ) / g, "" ) ;
186
+
187
+ return html . trim ( ) ;
188
+ } ;
189
+
127
190
// Helper to render the description markdown
128
191
const renderMarkdown = ( content : string ) => {
129
192
const convertedContent = convertJiraToMarkdown ( content ) ;
@@ -216,7 +279,10 @@ export function SupportDetail() {
216
279
const ticketData = await getTicket ( ticketId ) ;
217
280
if ( ticketData && ticketData . length === 1 ) {
218
281
setTicket ( ticketData [ 0 ] ) ;
219
- setNewDescription ( ticketData [ 0 ] . fields . description || '' ) ;
282
+
283
+ console . log ( "Description" , ticketData [ 0 ] . fields . description ) ;
284
+
285
+ setNewDescription ( convertJiraToHtml ( ticketData [ 0 ] . fields . description ) || '' ) ;
220
286
} else {
221
287
setError ( trans ( "support.ticketNotFound" ) ) ;
222
288
}
@@ -240,7 +306,8 @@ export function SupportDetail() {
240
306
const handleSaveDescription = async ( ) => {
241
307
setIsSavingDescription ( true ) ; // Start loading state
242
308
try {
243
- await updateTicketDescription ( ticketId , newDescription ) ;
309
+ const jiraFormattedDescription = convertHtmlToJiraMarkdown ( newDescription ) ;
310
+ await updateTicketDescription ( ticketId , jiraFormattedDescription ) ;
244
311
message . success ( trans ( "support.ticketDescriptionUpdated" ) ) ;
245
312
setIsEditingDescription ( false ) ;
246
313
} catch ( error ) {
@@ -309,9 +376,8 @@ export function SupportDetail() {
309
376
} else {
310
377
message . warning ( trans ( "support.ticketAttachmentEmpty" ) ) ;
311
378
}
312
- } ;
313
-
314
-
379
+ } ;
380
+
315
381
316
382
if ( loading ) {
317
383
return (
@@ -376,10 +442,16 @@ export function SupportDetail() {
376
442
< DescriptionWrapper >
377
443
{ isEditingDescription ? (
378
444
< >
379
- < TextArea
445
+ { /* <TextArea
380
446
rows={4}
381
447
value={newDescription}
382
448
onChange={(e) => setNewDescription(e.target.value)}
449
+ /> */ }
450
+ < ReactQuill
451
+ theme = "snow"
452
+ value = { newDescription }
453
+ onChange = { setNewDescription }
454
+ style = { { marginBottom : '8px' } }
383
455
/>
384
456
< Button
385
457
type = "primary"
0 commit comments