|
@@ -0,0 +1,243 @@
|
|
1
|
+import React from 'react'
|
|
2
|
+import HtmlDocumentComponent from '../component/HtmlDocument.jsx'
|
|
3
|
+import {
|
|
4
|
+ handleFetchResult,
|
|
5
|
+ PopinFixed,
|
|
6
|
+ PopinFixedHeader,
|
|
7
|
+ PopinFixedOption,
|
|
8
|
+ PopinFixedContent,
|
|
9
|
+ Timeline
|
|
10
|
+} from 'tracim_lib'
|
|
11
|
+import { FETCH_CONFIG, MODE, debug } from '../helper.js'
|
|
12
|
+import i18n from '../i18n.js'
|
|
13
|
+
|
|
14
|
+class HtmlDocument extends React.Component {
|
|
15
|
+ constructor (props) {
|
|
16
|
+ super(props)
|
|
17
|
+ this.state = {
|
|
18
|
+ appName: 'html-documents',
|
|
19
|
+ isVisible: true,
|
|
20
|
+ config: props.data ? props.data.config : debug.config,
|
|
21
|
+ loggedUser: props.data ? props.data.loggedUser : debug.loggedUser,
|
|
22
|
+ content: props.data ? props.data.content : debug.content,
|
|
23
|
+ timeline: props.data ? [] : [], // debug.timeline,
|
|
24
|
+ newComment: '',
|
|
25
|
+ mode: MODE.VIEW
|
|
26
|
+ }
|
|
27
|
+
|
|
28
|
+ document.addEventListener('appCustomEvent', this.customEventReducer)
|
|
29
|
+ }
|
|
30
|
+
|
|
31
|
+ customEventReducer = ({ detail: { type, data } }) => { // action: { type: '', data: {} }
|
|
32
|
+ switch (type) {
|
|
33
|
+ case 'html-documents_showApp':
|
|
34
|
+ this.setState({isVisible: true})
|
|
35
|
+ break
|
|
36
|
+ case 'html-documents_hideApp':
|
|
37
|
+ this.setState({isVisible: false})
|
|
38
|
+ break
|
|
39
|
+ case 'html-documents_reloadContent':
|
|
40
|
+ this.setState({content: data})
|
|
41
|
+ }
|
|
42
|
+ }
|
|
43
|
+
|
|
44
|
+ componentDidMount () {
|
|
45
|
+ console.log('HtmlDocument did mount')
|
|
46
|
+ if (this.state.content.content_id === -1) return // debug case
|
|
47
|
+
|
|
48
|
+ this.loadContent()
|
|
49
|
+ // wysiwyg()
|
|
50
|
+ }
|
|
51
|
+
|
|
52
|
+ componentDidUpdate (prevProps, prevState) {
|
|
53
|
+ console.log('HtmlDocument did update', prevState, this.state)
|
|
54
|
+ if (!prevState.content || !this.state.content) return
|
|
55
|
+
|
|
56
|
+ if (prevState.content.content_id !== this.state.content.content_id) {
|
|
57
|
+ this.loadContent()
|
|
58
|
+ }
|
|
59
|
+ }
|
|
60
|
+
|
|
61
|
+ loadContent = async () => {
|
|
62
|
+ const { content, config } = this.state
|
|
63
|
+
|
|
64
|
+ const fetchResultHtmlDocument = await fetch(`${config.apiUrl}/workspaces/${content.workspace_id}/html-documents/${content.content_id}`, { // ${content.workspace_id} ${content.content_id}
|
|
65
|
+ ...FETCH_CONFIG,
|
|
66
|
+ method: 'GET'
|
|
67
|
+ })
|
|
68
|
+ const fetchResultComment = await fetch(`${config.apiUrl}/workspaces/${content.workspace_id}/contents/${content.content_id}/comments`, { // ${content.workspace_id} ${content.content_id}
|
|
69
|
+ ...FETCH_CONFIG,
|
|
70
|
+ method: 'GET'
|
|
71
|
+ })
|
|
72
|
+ const fetchResultRevision = await fetch(`${config.apiUrl}/workspaces/${content.workspace_id}/html-documents/${content.content_id}/revisions`, { // ${content.workspace_id} ${content.content_id}
|
|
73
|
+ ...FETCH_CONFIG,
|
|
74
|
+ method: 'GET'
|
|
75
|
+ })
|
|
76
|
+
|
|
77
|
+ handleFetchResult(fetchResultHtmlDocument)
|
|
78
|
+ .then(resHtmlDocument => this.setState({content: resHtmlDocument.body}))
|
|
79
|
+ .catch(e => console.log('Error loading content.', e))
|
|
80
|
+
|
|
81
|
+ Promise.all([
|
|
82
|
+ handleFetchResult(fetchResultComment),
|
|
83
|
+ handleFetchResult(fetchResultRevision)
|
|
84
|
+ ])
|
|
85
|
+ .then(([resComment, resRevision]) => {
|
|
86
|
+ const resCommentWithProperDate = resComment.body.map(c => ({...c, created: (new Date(c.created)).toLocaleString()}))
|
|
87
|
+ const revisionWithComment = resRevision.body
|
|
88
|
+ .map(r => ({
|
|
89
|
+ ...r,
|
|
90
|
+ created: (new Date(r.created)).toLocaleString(),
|
|
91
|
+ timelineType: 'revision',
|
|
92
|
+ commentList: r.comments_ids.map(ci => ({
|
|
93
|
+ timelineType: 'comment',
|
|
94
|
+ ...resCommentWithProperDate.find(c => c.content_id === ci)
|
|
95
|
+ }))
|
|
96
|
+ }))
|
|
97
|
+ .reduce((acc, rev) => [
|
|
98
|
+ ...acc,
|
|
99
|
+ rev,
|
|
100
|
+ ...rev.commentList.map(comment => ({
|
|
101
|
+ ...comment,
|
|
102
|
+ customClass: '',
|
|
103
|
+ loggedUser: this.state.config.loggedUser
|
|
104
|
+ }))
|
|
105
|
+ ], [])
|
|
106
|
+
|
|
107
|
+ console.log(revisionWithComment)
|
|
108
|
+
|
|
109
|
+ this.setState({timeline: revisionWithComment})
|
|
110
|
+ })
|
|
111
|
+ .catch(e => {
|
|
112
|
+ console.log('Error loading Timeline.', e)
|
|
113
|
+ this.setState({timeline: []})
|
|
114
|
+ })
|
|
115
|
+ }
|
|
116
|
+
|
|
117
|
+ saveEditHtmlDocument = (label, rawContent) => fetch(`${this.state.config.apiUrl}/workspaces/${this.state.content.workspace_id}/html-documents/${this.state.content.content_id}`, {
|
|
118
|
+ ...FETCH_CONFIG,
|
|
119
|
+ method: 'PUT',
|
|
120
|
+ body: JSON.stringify({
|
|
121
|
+ label: label,
|
|
122
|
+ raw_content: rawContent
|
|
123
|
+ })
|
|
124
|
+ })
|
|
125
|
+
|
|
126
|
+ handleClickBtnCloseApp = () => {
|
|
127
|
+ this.setState({ isVisible: false })
|
|
128
|
+ GLOBAL_dispatchEvent({type: 'appClosed', data: {}})
|
|
129
|
+ }
|
|
130
|
+
|
|
131
|
+ handleSaveEditTitle = async newTitle => {
|
|
132
|
+ const fetchResultSaveHtmlDoc = await this.saveEditHtmlDocument(newTitle, this.state.content.raw_content)
|
|
133
|
+
|
|
134
|
+ handleFetchResult(fetchResultSaveHtmlDoc)
|
|
135
|
+ .then(resSave => {
|
|
136
|
+ if (resSave.apiResponse.status === 200) this.loadContent()
|
|
137
|
+ else console.warn('Error saving html-document. Result:', resSave, 'content:', this.state.content, 'config:', this.state.config)
|
|
138
|
+ })
|
|
139
|
+ }
|
|
140
|
+
|
|
141
|
+ handleClickNewVersion = () => {
|
|
142
|
+ this.setState({ mode: MODE.EDIT })
|
|
143
|
+ }
|
|
144
|
+
|
|
145
|
+ handleCloseNewVersion = () => {
|
|
146
|
+ this.setState({ mode: MODE.VIEW })
|
|
147
|
+ }
|
|
148
|
+
|
|
149
|
+ handleSaveHtmlDocument = async () => {
|
|
150
|
+ const { content, config } = this.state
|
|
151
|
+
|
|
152
|
+ const fetchResultSaveHtmlDoc = await this.saveEditHtmlDocument(content.label, content.raw_content)
|
|
153
|
+
|
|
154
|
+ handleFetchResult(fetchResultSaveHtmlDoc)
|
|
155
|
+ .then(resSave => {
|
|
156
|
+ if (resSave.apiResponse.status === 200) {
|
|
157
|
+ this.handleCloseNewVersion()
|
|
158
|
+ this.loadContent()
|
|
159
|
+ } else {
|
|
160
|
+ console.warn('Error saving html-document. Result:', resSave, 'content:', content, 'config:', config)
|
|
161
|
+ }
|
|
162
|
+ })
|
|
163
|
+ }
|
|
164
|
+
|
|
165
|
+ handleChangeText = e => {
|
|
166
|
+ const newText = e.target.value // because SyntheticEvent is pooled (react specificity
|
|
167
|
+ this.setState(prev => ({content: {...prev.content, raw_content: newText}}))
|
|
168
|
+ }
|
|
169
|
+
|
|
170
|
+ handleChangeNewComment = e => {
|
|
171
|
+ const newComment = e.target.value
|
|
172
|
+ this.setState({newComment})
|
|
173
|
+ }
|
|
174
|
+
|
|
175
|
+ handleClickValidateNewCommentBtn = async () => {
|
|
176
|
+ const { config, content, newComment } = this.state
|
|
177
|
+
|
|
178
|
+ const fetchResultSaveNewComment = await fetch(`${config.apiUrl}/workspaces/${content.workspace_id}/contents/${content.content_id}/comments`, {
|
|
179
|
+ ...FETCH_CONFIG,
|
|
180
|
+ method: 'POST',
|
|
181
|
+ body: JSON.stringify({
|
|
182
|
+ raw_content: newComment
|
|
183
|
+ })
|
|
184
|
+ })
|
|
185
|
+
|
|
186
|
+ handleFetchResult(fetchResultSaveNewComment)
|
|
187
|
+ .then(resSave => {
|
|
188
|
+ if (resSave.apiResponse.status === 200) {
|
|
189
|
+ this.setState({newComment: ''})
|
|
190
|
+ this.loadContent()
|
|
191
|
+ } else {
|
|
192
|
+ console.warn('Error saving html-document comment. Result:', resSave, 'content:', content, 'config:', config)
|
|
193
|
+ }
|
|
194
|
+ })
|
|
195
|
+ }
|
|
196
|
+
|
|
197
|
+ render () {
|
|
198
|
+ const { isVisible, loggedUser, content, timeline, newComment, config } = this.state
|
|
199
|
+
|
|
200
|
+ if (!isVisible) return null
|
|
201
|
+
|
|
202
|
+ return (
|
|
203
|
+ <PopinFixed customClass={`${config.slug}`}>
|
|
204
|
+ <PopinFixedHeader
|
|
205
|
+ customClass={`${config.slug}`}
|
|
206
|
+ faIcon={config.faIcon}
|
|
207
|
+ title={content.label}
|
|
208
|
+ onClickCloseBtn={this.handleClickBtnCloseApp}
|
|
209
|
+ onValidateChangeTitle={this.handleSaveEditTitle}
|
|
210
|
+ />
|
|
211
|
+
|
|
212
|
+ <PopinFixedOption
|
|
213
|
+ customClass={`${config.slug}`}
|
|
214
|
+ onClickNewVersionBtn={this.handleClickNewVersion}
|
|
215
|
+ i18n={i18n}
|
|
216
|
+ />
|
|
217
|
+
|
|
218
|
+ <PopinFixedContent customClass={`${config.slug}__contentpage`}>
|
|
219
|
+ <HtmlDocumentComponent
|
|
220
|
+ mode={this.state.mode}
|
|
221
|
+ onClickCloseEditMode={this.handleCloseNewVersion}
|
|
222
|
+ onClickValidateBtn={this.handleSaveHtmlDocument}
|
|
223
|
+ version={content.current_revision_id}
|
|
224
|
+ text={content.raw_content}
|
|
225
|
+ onChangeText={this.handleChangeText}
|
|
226
|
+ key={'html-documents'}
|
|
227
|
+ />
|
|
228
|
+
|
|
229
|
+ <Timeline
|
|
230
|
+ customClass={`${config.slug}__contentpage`}
|
|
231
|
+ loggedUser={loggedUser}
|
|
232
|
+ timelineData={timeline}
|
|
233
|
+ newComment={newComment}
|
|
234
|
+ onChangeNewComment={this.handleChangeNewComment}
|
|
235
|
+ onClickValidateNewCommentBtn={this.handleClickValidateNewCommentBtn}
|
|
236
|
+ />
|
|
237
|
+ </PopinFixedContent>
|
|
238
|
+ </PopinFixed>
|
|
239
|
+ )
|
|
240
|
+ }
|
|
241
|
+}
|
|
242
|
+
|
|
243
|
+export default HtmlDocument
|