@@ -6,13 +6,15 @@ import { useParams } from "react-router-dom";
66import { Descriptions , Tag , Avatar , Skeleton , Button , Typography , List , Table , Progress , Input , Upload , message } from "antd" ;
77import { UploadOutlined } from '@ant-design/icons' ;
88import 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' ;
1010import { Level1SettingPageContent , Level1SettingPageTitle } from "../setting/styled" ;
1111import { HeaderBack } from "../setting/permission/styledComponents" ;
1212import { SUPPORT_URL } from "constants/routesURL" ;
1313import { TacoMarkDown } from "lowcoder-design" ;
1414import remarkGfm from 'remark-gfm' ;
1515import { contrastColor } from "comps/controls/styleControlConstants" ;
16+ import ReactQuill from 'react-quill' ;
17+ import 'react-quill/dist/quill.snow.css' ;
1618
1719const { Title, Text } = Typography ;
1820const { TextArea } = Input ;
@@ -124,6 +126,67 @@ const convertJiraToMarkdown = (content: string) => {
124126 return content ;
125127} ;
126128
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+
127190// Helper to render the description markdown
128191const renderMarkdown = ( content : string ) => {
129192 const convertedContent = convertJiraToMarkdown ( content ) ;
@@ -216,7 +279,10 @@ export function SupportDetail() {
216279 const ticketData = await getTicket ( ticketId ) ;
217280 if ( ticketData && ticketData . length === 1 ) {
218281 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 ) || '' ) ;
220286 } else {
221287 setError ( trans ( "support.ticketNotFound" ) ) ;
222288 }
@@ -240,7 +306,8 @@ export function SupportDetail() {
240306 const handleSaveDescription = async ( ) => {
241307 setIsSavingDescription ( true ) ; // Start loading state
242308 try {
243- await updateTicketDescription ( ticketId , newDescription ) ;
309+ const jiraFormattedDescription = convertHtmlToJiraMarkdown ( newDescription ) ;
310+ await updateTicketDescription ( ticketId , jiraFormattedDescription ) ;
244311 message . success ( trans ( "support.ticketDescriptionUpdated" ) ) ;
245312 setIsEditingDescription ( false ) ;
246313 } catch ( error ) {
@@ -309,9 +376,8 @@ export function SupportDetail() {
309376 } else {
310377 message . warning ( trans ( "support.ticketAttachmentEmpty" ) ) ;
311378 }
312- } ;
313-
314-
379+ } ;
380+
315381
316382 if ( loading ) {
317383 return (
@@ -376,10 +442,16 @@ export function SupportDetail() {
376442 < DescriptionWrapper >
377443 { isEditingDescription ? (
378444 < >
379- < TextArea
445+ { /* <TextArea
380446 rows={4}
381447 value={newDescription}
382448 onChange={(e) => setNewDescription(e.target.value)}
449+ /> */ }
450+ < ReactQuill
451+ theme = "snow"
452+ value = { newDescription }
453+ onChange = { setNewDescription }
454+ style = { { marginBottom : '8px' } }
383455 />
384456 < Button
385457 type = "primary"
0 commit comments